如何使用Python中的正则表达式从文本中提取信息?

时间:2012-07-15 14:47:41

标签: python regex text-formatting

我有以下输入。我想将其解析为CSV分隔的字符串。我可以通过正则表达式模式获得SKU,但由于我是正则表达式解析的新手,我不知道复杂的模式。如果有人能帮我解决这个问题会很好。

谢谢!

    charset="iso-8859-1"


BODY {


}



TD {



}



TH {


}



H1 {


}

TABLE,IMG,A {


}

**PO Number:** 35102


**Ship To:**  


Georgie Clements



6902 Stonegate Drive

Odessa, TX 79765



432-363-8459


SKU



Product



Qty


JJ-Rug-Zebra-PK



Zebra Pink Rug



1

JJ-Zebra-PK-Twin-4



Zebra Pink 4 Piece Twin Comforter Set



1



JJ-TwinSheets-Zebra-PK



Zebra Pink 3 Piece Twin Sheet Set



1




JJ-Memo-Zebra-PK



Zebra Pink Memory Board



1

我希望它的格式如下:

PONumber, Shipping info, SKU, Product, Qty
'35102', '[ShipToAddress]', 'JJ-Rug-Zebra-PK', 'Zebra Pink Rug', '1'
'35102', '[ShipToAddress]', 'JJ-Zebra-PK-Twin-4', 'Zebra Pink 4 Piece Twin Comforter Set', '1'
'35102', '[ShipToAddress]', 'JJ-TwinSheets-Zebra-PK', 'Zebra Pink 3 Piece Twin Sheet Set', '1'
'35102', '[ShipToAddress]', 'JJ-Memo-Zebra-PK', 'Zebra Pink Memory Board', '1'

目前的代码如下:

pattern = re.compile(r'(\b\w*JJ-\S*)') 

pos = 0 
    while True: 
        match = pattern.search(msgStr, pos) 
        if not match: 
            break 
        a = match.start() 
        e = match.end() 
        print ' %2d : %2d = %s' % (a, e-1, msgStr[a:e]) 
        pos = e

2 个答案:

答案 0 :(得分:1)

根据评论,这种输入数据更适合于有状态解析方法而不是正则表达式解决方案。某些行指示解析状态应该更改以捕获新的数据集。

理想情况下,首先你会看到这个数据源是否在JSON中可用,而不是我认为是HTML的网页编写。拥有JSON源将使此过程变得微不足道,因为数据已经是对象格式。

如果您唯一的选择是使用这种逐行来源,那么最好使用类似pyparsing之类的东西,或者根据您的需要将其视为过度杀戮,您可以循环使用并检查每一个,看看你是否应该开始或停止收集一种数据直到下一个令牌。

作为最后的手段,您可以在整个输入上运行多个正则表达式模式。您必须在整个输入上运行它的原因是因为您的数据跨越了行。捕获SKU / Product / Qty的基本正则表达式可能是:

re.findall(r'(JJ-[\w-]+)\n+(.*?)\n+(\d+)\n', dataStr)
#[('JJ-Rug-Zebra-PK', 'Zebra Pink Rug', '1'),
# ('JJ-Zebra-PK-Twin-4', 'Zebra Pink 4 Piece Twin Comforter Set', '1'),
# ('JJ-TwinSheets-Zebra-PK', 'Zebra Pink 3 Piece Twin Sheet Set', '1'),
# ('JJ-Memo-Zebra-PK', 'Zebra Pink Memory Board', '1')]

这将找到包含这些模式的每3行并返回元组列表。我真的不推荐正则表达式方法,但它是一个选项。

其他正则表达方式:

re.search(r'\*{2}PO Number:\*{2}\s(\d+)\n', dataStr)
#('35102',)

re.search(r'\*{2}Ship To:\*{2}\s+(.*?)\s+SKU', dataStr, re.DOTALL)
#('John Doe\n6902 Stonegate Drive\nOdessa, TX 79\n000-000-0000',)

您可以看到如何为每个数据位构建单独的正则表达式。

答案 1 :(得分:1)

这是另一种解决方案,不使用正则表达式:

s = "(your data as a single multiline string)"

datalines = lambda s: [ln for ln in (line.strip() for line in s.splitlines()) if ln]

_, _, po_number, _, rem = s.split('**')
shipto, data = rem.split('SKU', 1)

po_number = datalines(po_number)[0]
shipto    = '\n'.join(datalines(shipto))
data      = datalines(data)[2:]

res = [[po_number, shipto, sku, prod, qty] for sku,prod,qty in zip(*([iter(data)]*3))]

给出最终结果

[
    ['35102', 'Georgie Clements\n6902 Stonegate Drive\nOdessa, TX 79765\n432-363-8459', 'JJ-Rug-Zebra-PK', 'Zebra Pink Rug', '1'],
    ['35102', 'Georgie Clements\n6902 Stonegate Drive\nOdessa, TX 79765\n432-363-8459', 'JJ-Zebra-PK-Twin-4', 'Zebra Pink 4 Piece Twin Comforter Set', '1'],
    ['35102', 'Georgie Clements\n6902 Stonegate Drive\nOdessa, TX 79765\n432-363-8459', 'JJ-TwinSheets-Zebra-PK', 'Zebra Pink 3 Piece Twin Sheet Set', '1'],
    ['35102', 'Georgie Clements\n6902 Stonegate Drive\nOdessa, TX 79765\n432-363-8459', 'JJ-Memo-Zebra-PK', 'Zebra Pink Memory Board', '1']

编辑:第二个数据文件返回

[
    ['35104', 'Angelica Alvarado\n669 66th St.\nSpringfield, OR 97478\n5412322525', 'JJ-CribSheet-Cheetah-PK-PRT', 'Cheetah Pink Print Microsuede Crib Sheet', '1']
]

哪次检查似乎是正确的?


最终摘要:我发现他使用html2text将html电子邮件转换为文本,然后尝试解析它。解决方案是使用BeautifulSoup直接解析html,利用页面结构来识别他想要的字段。