2010-06-05 109 views
1

我想我會拼湊一個快速腳本來整合我已經分佈在多個CSS文件中的CSS規則,然後我可以縮小它。Python字典鍵缺失

我是新來的Python,但認爲這將是一個很好的練習來嘗試一種新的語言。我的主循環不像我想的那樣解析CSS。

我使用從CSS文件解析的選擇器填充一個列表以按順序返回CSS規則。在該腳本的後面,該列表包含在字典中找不到的元素。

for line in self.file.readlines(): 
     if self.hasSelector(line): 
     selector = self.getSelector(line) 
     if selector not in self.order: 
      self.order.append(selector) 
     elif selector and self.hasProperty(line): 
     # rules.setdefault(selector,[]).append(self.getProperty(line)) 
     property = self.getProperty(line) 
     properties = [] if selector not in rules else rules[selector] 
     if property not in properties: 
      properties.append(property) 
     rules[selector] = properties 
     # print "%s :: %s" % (selector, "".join(rules[selector])) 
    return rules 

遇到的錯誤:

$ css-combine combined.css test1.css test2.css 
Traceback (most recent call last): 
    File "css-combine", line 108, in <module> 
    c.run(outfile, stylesheets) 
    File "css-combine", line 64, in run 
    [(selector, rules[selector]) for selector in parser.order], 
KeyError: 'p' 

交換輸入:

$ css-combine combined.css test2.css test1.css 
Traceback (most recent call last): 
    File "css-combine", line 108, in <module> 
    c.run(outfile, stylesheets) 
    File "css-combine", line 64, in run 
    [(selector, rules[selector]) for selector in parser.order], 
KeyError: '#header_.title' 

我在做的情況下像子空間代碼中的一些古怪的事情下劃線在字典鍵將其命名爲是一個問題 - 也許這是一個溫和的預防措施?根據輸入的順序,字典中找不到一個不同的鍵。

腳本:

#!/usr/bin/env python 

import optparse 
import re 

class CssParser: 

    def __init__(self): 
    self.file = False 
    self.order = [] # store rules assignment order 

    def parse(self, rules = {}): 
    if self.file == False: 
     raise IOError("No file to parse") 

    selector = False 
    for line in self.file.readlines(): 
     if self.hasSelector(line): 
     selector = self.getSelector(line) 
     if selector not in self.order: 
      self.order.append(selector) 
     elif selector and self.hasProperty(line): 
     # rules.setdefault(selector,[]).append(self.getProperty(line)) 
     property = self.getProperty(line) 
     properties = [] if selector not in rules else rules[selector] 
     if property not in properties: 
      properties.append(property) 
     rules[selector] = properties 
     # print "%s :: %s" % (selector, "".join(rules[selector])) 
    return rules 

    def hasSelector(self, line): 
    return True if re.search("^([#a-z,\.:\s]+){", line) else False 

    def getSelector(self, line): 
    s = re.search("^([#a-z,:\.\s]+){", line).group(1) 
    return "_".join(s.strip().split()) 

    def hasProperty(self, line): 
    return True if re.search("^\s?[a-z-]+:[^;]+;", line) else False 

    def getProperty(self, line): 
    return re.search("([a-z-]+:[^;]+;)", line).group(1) 


class Consolidator: 
    """Class to consolidate CSS rule attributes""" 

    def run(self, outfile, files): 
    parser = CssParser() 
    rules = {} 
    for file in files: 
     try: 
     parser.file = open(file) 
     rules = parser.parse(rules) 
     except IOError: 
     print "Cannot read file: " + file 
     finally: 
     parser.file.close() 

    self.serialize(
     [(selector, rules[selector]) for selector in parser.order], 
     outfile 
    ) 

    def serialize(self, rules, outfile): 
    try: 
     f = open(outfile, "w") 
     for rule in rules: 
     f.write(
      "%s {\n\t%s\n}\n\n" % (
      " ".join(rule[0].split("_")), "\n\t".join(rule[1]) 
     ) 
     ) 
    except IOError: 
     print "Cannot write output to: " + outfile 
    finally: 
     f.close() 

def init(): 
    op = optparse.OptionParser(
    usage="Usage: %prog [options] <output file> <stylesheet1> " + 
     "<stylesheet2> ... <stylesheetN>", 
    description="Combine CSS rules spread across multiple " + 
     "stylesheets into a single file" 
) 
    opts, args = op.parse_args() 
    if len(args) < 3: 
    if len(args) == 1: 
     print "Error: No input files specified.\n" 
    elif len(args) == 2: 
     print "Error: One input file specified, nothing to combine.\n" 
    op.print_help(); 
    exit(-1) 

    return [opts, args] 

if __name__ == '__main__': 
    opts, args = init() 
    outfile, stylesheets = [args[0], args[1:]] 
    c = Consolidator() 
    c.run(outfile, stylesheets) 

測試CSS文件1:

body { 
    background-color: #e7e7e7; 
} 

p { 
    margin: 1em 0em;  
} 

文件2:

body { 
    font-size: 16px; 
} 

#header .title { 
    font-family: Tahoma, Geneva, sans-serif; 
    font-size: 1.9em; 
} 

#header .title a, #header .title a:hover { 
    color: #f5f5f5; 
    border-bottom: none; 
    text-shadow: 2px 2px 3px rgba(0, 0, 0, 1); 
} 

在此先感謝。

+0

對正則表達式'r「」'使用原始字符串文字。你可以使用're.match'而不是're.search(「^ ...'。'return如果x else False可以被'return x'或'return bool(x)'代替,則返回True。 – jfs 2010-06-05 13:26:28

回答

3

變化

def hasProperty(self, line): 
    return True if re.search("^\s?[a-z-]+:[^;]+;", line) else False 

def hasProperty(self, line): 
    return True if re.search("^\s*[a-z-]+:[^;]+;", line) else False 

hasProperty不匹配任何東西,因爲\s?比賽只有0或1空白字符。

+0

+1謝謝,通常它是這麼小的東西!它解釋了爲什麼顯然隨機屬性在'combined.css'中也丟失了,它們是以多個空格而不是一個製表符作爲前綴的行。 – 2010-06-05 15:00:25