【问题标题】:Python dictionary key missingPython字典键丢失
【发布时间】:2010-06-05 12:48:21
【问题描述】:

我想我应该编写一个快速脚本来整合我分布在多个 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);
}

提前致谢。

【问题讨论】:

  • 对正则表达式 r"" 使用原始字符串文字。您可以使用re.match 代替re.search("^...return True if x else False 可以替换为 return xreturn bool(x)

标签: python parsing dictionary list


【解决方案1】:

改变

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

【讨论】:

  • +1 谢谢,这么小的东西很典型!它解释了为什么 combined.css 中也缺少明显的随机属性,它们是以多个空格而不是一个制表符为前缀的行。
猜你喜欢
  • 2021-01-28
  • 2013-11-11
  • 1970-01-01
  • 2020-12-25
  • 2017-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多