从YAML文件中解析正则表达式会增加额外的内容。

1 人不认可

我有一堆正则表达式,用来从一个文本文件中抓取很多特定字段。当直接在Python脚本中使用时,这些都能正常工作。

但我想到把它们放在YAML文件中,然后从那里读取。下面是它的样子。

# Document file for Regular expression patterns for a company invoice
    issuer: ABCCorp
    fields:
      invoice_number: INVOICE\s*(\S+)
      invoice_date: INVOICE DATE\s*(\S+)
      cusotmer_id: CUSTOMER ID\s*(\S+)
      origin: ORIGIN\s*(.*)ETD
      destination: DESTINATION\s*(.*)ETA
      sub_total: SUBTOTAL\s*(\S+)
      add_gst: SUBTOTAL\s*(\S+)
      total_cost: TOTAL USD\s*(\S+)
      description_breakdown: (?s)(DESCRIPTION\s*GST IN USD\s*.+?TOTAL CHARGES)
      package_details_fields: (?s)(WEIGHT\s*VOLUME\s*.+?FLIGHT|ROAD REFERENCE)
      mawb_hawb: (?s)((FLIGHT|ROAD REFERENCE).*(MAWB|MASTER BILL)\s*.+?GOODS COLLECTED FROM)

当我在python中使用pyyml检索时,它在周围添加了一个字符串引号(这很好,因为我可以在后面添加r''),但我看到它也在regex之间添加了额外的\。这将使重码在代码中使用时出错。

import yaml
with open(os.path.join(TEMPLATES_DIR,"regex_template.yml")) as f:
    my_dict = yaml.safe_load(f)
print(my_dict)
{'issuer': 'ABCCorp', 'fields': {'invoice_number': 'INVOICE\\s*(\\S+)', 'invoice_date': 'INVOICE DATE\\s*(\\S+)', 'cusotmer_id': 'CUSTOMER ID\\s*(\\S+)', 'origin': 'ORIGIN\\s*(.*)ETD', 'destination': 'DESTINATION\\s*(.*)ETA', 'sub_total': 'SUBTOTAL\\s*(\\S+)', 'add_gst': 'SUBTOTAL\\s*(\\S+)', 'total_cost': 'TOTAL USD\\s*(\\S+)', 'description_breakdown': '(?s)(DESCRIPTION\\s*GST IN USD\\s*.+?TOTAL CHARGES)', 'package_details_fields': '(?s)(WEIGHT\\s*VOLUME\\s*.+?FLIGHT|ROAD REFERENCE)', 'mawb_hawb'

如何读取我在yaml文件中的正确的regex?在yaml文件中写的任何字符串在python中读取时都会有一个引号,因为那是一个字符串吗?

EDIT:

yaml文件中的主要铰链是。

INVOICE\s*(\S+)

Output in dict is:

'INVOICE\\s*(\\S+)'
    
5 个评论
你是什么意思,它是 "在regex之间添加额外的\"?
我将添加编辑。
如果你检查yaml文件中的输入,regex和dict输出,dict在regex之间有额外的\。
我并没有给它降权。顺便说一下,是'之间'让我感到不舒服。进入 python ,没有争论。在 >>> 提示下输入。 d = {'x': r'ab\sc'}; print(d) 。你会看到。 {'x': 'ab\\sc'} 。我不认为你有一个额外的反斜线。双反斜线是你在字符串中输入单反斜线的方式。"
我不确定我是否理解它。我也是这样做的:d = {'x': 'ab\sc'}; print(d) 而且它仍然显示2\。 为什么它要加上这个?当我现在从dict中读取gex时,这将会给我带来问题,因为它将会在gex中读取2\,而原始gex并没有这样的内容。
python
regex
Baktaawar
Baktaawar
发布于 2020-05-07
1 个回答
Booboo
Booboo
发布于 2020-05-07
已采纳
0 人赞同

这段话太长了,不能作为评论来做。

反斜线字符用于转义特殊字符。比如说。

'\n': newline
'\a': alarm

当你在一个没有特殊意义的字母前使用它时,它只是被认为是一个反斜杠字符。

'\s': backslash followed by 's'

但可以肯定的是,每当你想在一个字符串中输入反斜杠字符而又不想让它被解释为转义序列的开始时,你就把它加倍。

'\\s': also a backslash followed by a 's'
'\\a': a backslash followed by a 'a'

如果你使用r''类型的文字,那么反斜线永远不会被解释为转义序列的开始。

r'\a': a backslash followed by 'a' (not an alarm character)
r'\n': a backslash followed by n (not a newline -- however when used in a regex. it will match a newline)

Now here is the punchline:

当你打印出这些Python对象时,例如:。

d = {'x': 'ab\sd'}
print(d)

Python 将打印字典的字符串表示法,字符串将打印。 'ab\\sd'。如果你刚刚做了

print('ab\sd')

你会看到ab\sd。相当大的差异。

为什么会有这种差别。看看这是否有意义。

d = {'x': 'ab\ncd'}
print(d)
print('ab\ncd')

Results:

d = {'x': 'ab\ncd'}

底线是,当你打印一个不是字符串的 Python 对象时,它会打印出该对象的表示,显示你是如何创建它的。如果该对象包含一个字符串,并且该字符串包含一个反斜杠,那么你在输入反斜杠时就会把它加倍。

要处理你的my_dict。由于你没有提供my_dict的完整值,我只能使用一个截断的版本作为演示。但这将证明my_dict有完全好的正则表达式。

import re
my_dict = {'issuer': 'ABCCorp', 'fields': {'invoice_number': 'INVOICE\\s*(\\S+)', 'invoice_date': 'INVOICE DATE\\s*(\\S+)'}}
fields = my_dict['fields']
invoice_number_re = fields['invoice_number']
m = re.search(invoice_number_re, 'blah-blah INVOICE 12345 blah-blah')
print(m[1])

Prints:

12345

如果你要反复使用相同的正则表达式,那么最好是对它们进行编译。

import re
my_dict = {'issuer': 'ABCCorp', 'fields': {'invoice_number': 'INVOICE\\s*(\\S+)', 'invoice_date': 'INVOICE DATE\\s*(\\S+)'}}
#compile the strings to regular expressions
fields = my_dict['fields']
for k, v in fields.items():
    fields[k] = re.compile(v)