代码之家  ›  专栏  ›  技术社区  ›  Greg K

缺少python字典键

  •  1
  • Greg K  · 技术社区  · 14 年前

    我想我应该编写一个快速脚本来整合我在多个CSS文件中分发的CSS规则,然后我可以缩小它。

    我对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);
    }
    

    事先谢谢。

    1 回复  |  直到 14 年前
        1
  •  3
  •   unutbu    14 年前

    变化

    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个空白字符。