Python - 在字典中查找重复出现的 pairs/groups 个值

Python - find recurring pairs/groups of values in dictionary

我有以下脚本,它循环遍历 css 规则的文本文件,并将每个规则及其属性存储在字典中(欢迎改进代码,我才刚刚开始使用 Python):

findGroups.py

import sys
source = sys.argv[1]
temp = open('pythonTestFile.txt', 'w+')
di = {}
with open(source, 'r') as infile:
    for line in infile:
        # if line starts with . or #, contains _ or - between 
        # words and has a space and opening brace(ie is css rule name)
        if re.search('((([\.\-\'])?\w+\s?\{', line):
           key = line.replace("{", "")
           di[key] = []
           line = next(file)
           while "}" not in line:
               # remove trailing whitespace and \n 
               line = ' '.join(line.split())
               di[key].append(line)
               line = next(infile)
temp.close();

source.txt

* {
    min-height: 1000px;
    overflow: hidden;
}

.leftContainerDiv {
    font-family: Helvetica;
    font-size: 10px;
    background: white;
}

#cs_ht_panel{   
    font-family:10px;
    display:block;
    font-family:Helvetica;
    width:auto;
}
//...etc

我希望输出看起来像这样(也欢迎提出可读性建议):

pythonTestFile.txt

Group 1, count(2) - font-family: Helvetica; + font-size: 10px;
Group 2: //...etc

我现在想做的是弄清楚哪些 css 属性是重复出现的组,例如,如果 font-size: 10px 和 font-family: Helvetica 在规则中一起出现,这个组是否出现在任何其他规则中以及它出现了多少次。

我不完全确定该去哪里,我什至不知道如何开始某种比较算法,或者字典是否是存储文本的正确数据结构。

编辑:作为对评论的回应,我无法使用第三方库。此脚本将在 Red Hat VM 上使用,并且只能将预先批准的软件推送到这些上,我无法只下载库或软件包

给每个css属性分配一个不同的素数,比如:

{
    'diplay: block': 2
    'font-size: 10px': 3,
    'font-family: Helvetica': 5,
    'min-height: 1000px': 7,
    'overflow: hidden': 11,
    'width: auto': 13,
    'background: white': 17,
}

然后做一个字典,其中键是 css 选择器(你称之为 "rules"),值是它具有的所有属性的乘积:

{
    '#cs_ht_panel': 390, # 2 * 3 * 5 * 13
    '*': 77, # 7 * 11
    '.leftContainerDiv': 255, # 3 * 5 * 17
}

现在您可以轻松确定两件事:

  • 哪些选择器 ("rules") 具有 属性 x(由其质数表示)或一组属性 {x,y,z,..}(由其质数的乘积表示) ) 通过查看选择器编号是否可以被该编号整除。
    例如什么选择器同时具有 'font-family: Helvetica' (5) 和 font-size: 10px (3)?所有且仅能被 15 整除的那些。
  • 通过计算 GCD(最大公约数),两个选择器共有的所有属性。
    例如GCD(390, 77) = 1 -> 它们没有共同的属性
    GCD(390, 255) = 15 -> 分解 -> 3 * 5

您还可以通过遍历所有选择器值来找到最常见的组,找到所有不是素数的适当除数,并保留一个字典来保存找到该除数的数字。每个除数都是一个群,你可以通过分解它来找到它的元素。

  • 390 -> 6 10 15 26 30 39 65 78 130 195
  • 255 -> 15 51 85
  • 77 ->

所以你有两次 15,其他所有 1 次。也就是说15这个组出现了2次,也就是属性3和5的组

最后一个计算步骤是 2^n,其中 n 是 css 选择器中的属性数。这应该不是问题,因为大多数选择器的属性都少于 10 个,但如果属性超过 20 个,您就会遇到麻烦。我建议通过删除前缀(moz-、webkit-)和后缀(-left、-right、-top、-bottom)来压缩属性

你可以(而且可能应该,对于真正的 CSS 有数百行的文件)只使用集合和它们的操作(交集等)而不是数字、乘积和素数;但这不是更酷吗? ;)

基于上述想法的解决方案 - 我使用的是集合和有序列表,而不是使用质数。也许这就是你想要的?

import re
import itertools

f = open('css_test.txt', 'r')
lines = f.readlines()
lines_str = ' '.join([l.strip() for l in lines])
#print lines_str

r = re.compile(r'.*?{(.*?)}') # Get All strings between {}
groups = r.findall(lines_str)
#print groups

# remove any stray spaces in the string and create groups of attributes like
# style: value
grps = []
for grp in groups:
    grps.append(filter(lambda x: len(x) > 0, grp.strip().split(';')))


# clean up those style: value attributes so that we get 'style:value'
# without any spaces and also collect all such attributes (we'd later create
# a set of these attributes)
grps2 = []
all_keys = []
for grp in grps:
    grp2 = []
    for g in grp:
        x = ':'.join([x.strip() for x in g.split(':')])
        grp2.append(x)
        all_keys.append(x)
    grps2.append(grp2)
set_keys = set(sorted(all_keys))

print set_keys
print '***********'
set_dict = {}
# For each combination of 2 of keys in the set find intersection of this
# set with the set of keys in the cleaned up groups above
# if intersection is the set of 2 keys: initialize a dictionary or add 1
for x in itertools.combinations(set_keys, 2):
    for g in grps2:
        set_x = set(x)
        set_g = set(g)
        #print "set_g : ", set_g
        if set_x  & set_g == set_x:
            print set_x
            if set_dict.has_key(x):
                set_dict[x] += 1
            else:
                set_dict[x] = 1

# print everything
print set_dict

即使此解决方案与您想要的不完全匹配 - 也许您可以按照上述思路得出您想要做的事情?