Python中的不规则字符串解析

时间:2011-10-08 16:06:18

标签: python django string parsing web

我是python / django的新手,我正试图从我的刮刀中获取更有效的信息。目前,刮刀获取漫画书标题列表并正确地将它们分成三个部分(发布日期,原始日期和标题)的CSV列表。然后我将当前日期和标题传递到我的数据库的不同部分,我在我的Loader脚本中执行(将mm / dd / yy转换为yyyy-mm-dd,保存到“pub_date”列,标题转到“title”柱)。

常见字符串可能如下所示:

10/12/11|10/12/11|Stan Lee's Traveler #12 (10 Copy Incentive Cover)

我成功地抓住了日期,但标题更加棘手。在这种情况下,我理想地希望在第二个“|”之后用三个不同的列填充信息。标题应该是“标题”,一个charfield。数字12(在'#'之后)应该进入DecimalField“issue_num”,并且'()'之间的所有内容都应该进入“特殊”字段。我不知道如何进行这种严格的解析。

有时,有多个#(特别是一个漫画被描述为一个包,“包含问题#90-#95”),有几个有'(')组(例如,“背叛地球”)猿人#1(4)(25份复制奖励封面) )

开始解决这个问题的好路是什么?我对If / else语句的了解很快就因为更复杂的行而分崩离析。我怎样才能有效地(如果可能的话)pythonic-ly解析这些行并细分它们以便我以后可以将它们插入数据库中的正确位置?

3 个答案:

答案 0 :(得分:1)

使用regular expression模块re。例如,如果您在变量|中拥有样本记录的第三个s - 分隔字段,则可以执行

match = re.match(r"^(?P<title>[^#]*) #(?P<num>[0-9]+) \((?P<special>.*)\)$", s)
title = match.groups('title')
issue = match.groups('num')
special = match.groups('special')

在最后三行中,您将获得一个缺失字段的IndexError。调整RE,直到它解析你想要的一切。

答案 1 :(得分:1)

解析标题是困难的部分,听起来你可以自己处理日期等。问题是没有一个规则可以解析每个标题,但有许多规则,你只能猜测哪一个适用于特定标题。

我通常会通过创建一个规则列表来处理这个问题,从最具体到一般,然后逐个尝试直到匹配。

要编写此类规则,您可以使用re模块甚至pyparsing

一般的想法是这样的:

class CantParse(Exception): 
    pass

# one rule to parse one kind of title
import re
def title_with_special( title ):
    """ accepts only a title of the form
     <text> #<issue> (<special>) """
    m = re.match(r"[^#]*#(\d+) \(([^)]+)\)", title)
    if m:
        return m.group(1), m.group(2)
    else:
        raise CantParse(title)


def parse_extra(title, rules):
    """ tries to parse extra information from a title using the rules """
    for rule in rules:
        try:
            return rule(title)
        except CantParse:
            pass

    # nothing matched
    raise CantParse(title)


# lets try this out
rules = [title_with_special] # list of rules to apply, add more functions here
titles = ["Stan Lee's Traveler #12 (10 Copy Incentive Cover)",
          "Betrayal Of The Planet Of The Apes #1 (Of 4)(25 Copy Incentive Cover) )"]

for title in titles:
    try:
        issue, special = parse_extra(title, rules)
        print "Parsed", title, "to issue=%s special='%s'" % (issue, special)
    except CantParse:
        print "No matching rule for", title

正如您所看到的那样,第一个标题被正确解析,而不是第二个。您必须编写一系列规则来解释数据中每种可能的标题格式。

答案 2 :(得分:1)

正则表达是要走的路。但是如果你不舒服地写它们,你可以试一下我写的小解析器(https://github.com/hgrecco/stringparser)。它将字符串格式(PEP 3101)转换为正则表达式。在您的情况下,您将执行以下操作:

>>> from stringparser import Parser
>>> p = Parser(r"{date:s}\|{date2:s}\|{title:s}#{issue:d} \({special:s}\)")
>>> x = p("10/12/11|10/12/11|Stan Lee's Traveler #12 (10 Copy Incentive Cover)")
OrderedDict([('date', '10/12/11'), ('date2', '10/12/11'), ('title', "Stan Lee's Traveler "), ('issue', 12), ('special', '10 Copy Incentive Cover')])
>>> x.issue
12

这种情况下的输出是(有序)字典。这适用于任何简单的情况,您可以调整它以捕获多个问题或多个()

还有一件事:请注意,在当前版本中,您需要手动转义正则表达式字符(即,如果要查找|,则需要键入\ |)。我打算很快改变这一点。