在Python中匹配字符串的特定模式后获取数字

时间:2019-03-08 15:08:55

标签: python regex string-matching

我想获取所有匹配的数字(仅数字示例“ 0012--22”)或包含与之对应的文本(例如“ RF332”)的数字,这些文本与所提供的字符串列表相匹配(“ my_list”代码)。带数字的文本的显示格式就像是由一两个空格隔开。提供样本输入文件以供参考。

这是输入文件:

$cat input_file
some text before Expedien: 1-21-212-16-26 some random text
Reference RE9833 of all sentences.
abc
123
456
something blah blah Ref.: 
tramite  1234567
Ref.:
some junk Expedien N° 18-00777 # some new content
some text Expedien N°18-0022995 # some garbled content

到目前为止,该脚本的附件如下:当前仅标识一个元素为{'tramite':'1234567'}

import re
import glob
import os

my_list = ['Ref.:', 'Reference', 'tramite', 'Expediente', 'Expediente No', 'Expedien N°', 'Exp.No', 'Expedien']

#open the file as input
with open('garb.txt','r') as infile:
  res = dict()
  for line in infile:  
    elems = re.split('(?::)?\s+', line)
    #print(elems)
    if len(elems) >= 2 :
      contains = False
      tmp = ''
      for elem in elems:  
        if contains:
          res.update({tmp : elem})
          print(res)
          contains = False
          break
        if elem in my_list:
          contains = True
          tmp = elem
  #print(res)

这是预期的输出:

示例输出:

{'Expedien N°': '18-0022995'}
{'Expedien N°': '18-0022995'}
{'Expedien': '1-21-212-16-26'}
{'Reference' : 'RE9833'}

等等等

2 个答案:

答案 0 :(得分:2)

您可以使用

(?<!\w)(your|escaped|keywords|here)\W*([A-Z]*\d+(?:-+[A-Z]*\d+)*)

请参见regex demo

模式详细信息

  • (?<!\w)-左侧单词边界(明确,\b的含义取决于上下文,如果下一个字符是非单词char,则它将在左侧要求一个单词char,而并非是用户通常期望的东西)
  • (your|escaped|keywords|here)-捕获第1组:您的关键字列表,可以使用'|'.join(map(re.escape,my_list))轻松构建(注意re.escape是转义.之类的特殊正则表达式元字符所必需的, +([等)
  • \W*-0+个非单词字符(字母,数字或_以外的字符)
  • ([A-Z]*\d+(?:-+[A-Z]*\d+)*)-捕获组2:
    • [A-Z]*-零个或多个大写ASCII字母
    • \d+-1个或更多数字
    • (?:-+[A-Z]*\d+)*-重复0次或更多次
      • -+-一个或多个连字符
      • [A-Z]*\d+-零个或多个大写ASCII字母,一个或多个数字

请参见Python demo

import re
s="""your_text_here"""
my_list = ['Ref.:', 'Reference', 'tramite', 'Expediente', 'Expediente No', 'Expedien N°', 'Exp.No', 'Expedien']
rx = r'(?<!\w)({})\W*([A-Z]*\d+(?:-+[A-Z]*\d+)*)'.format('|'.join(map(re.escape,my_list)))
print(re.findall(rx, s))

输出:

[('Expedien', '1-21-212-16-26'), ('Reference', 'RE9833'), ('tramite', '1234567'), ('Expedien N°', '18-00777'), ('Expedien N°', '18-0022995')]

答案 1 :(得分:1)

确实有必要允许少于50个代表点的用户发表评论,因为该线程是我非常好奇并希望分叉但又不想拥有的线程给出完整的答案,因为我给出的答案涉及有限的情况,而且不灵活。

@Wiktor Stribiewew

您的解决方案缺少“参考”。根据您的演示输出的一部分。看来他想跳过“ tramite”

@checkmate

在所需的输出中,您需要对其进行编辑,因为“ UV1234”不会显示在您发布的字符串中的任何地方

无论如何,我找到了解决方案,但我确实希望有人可以对此进行改进。

>>> import re

>>> string = '''some text before Expedien: 1-21-212-16-26 some random text
Reference RE9833 of all sentences.
abc
123
456
something blah blah Ref.: 
tramite  1234567
Ref.:
some junk Expedien N° 18-00777 # some new content
some text Expedien N°18-0022995 # some garbled content'''

>>> re.findall('(?:(Expedien[\s]+N\S|Ref\.(?!:[\S\s]{,11}Expedien)|Reference|Expedien))[\S\s]*?([A-Z\-]*(?:[\d]+)[\S]*)', string)

[('Expedien', '1-21-212-16-26'), ('Reference', 'RE9833'), ('Ref.', '1234567'), ('Expedien N\xb0', '18-00777'), ('Expedien N\xb0', '18-0022995')]

缺陷:

  • 要正确捕获,部分取决于“ Ref。(?!:[\ S \ s] {,11} Expedien)”
  • 首先需要对“ 11”进行编辑,以解决可能出现的其他信息长度,因此它不灵活
  • 第二,如果后面是“参考”而不是第三个“参考”。将被错误捕获
相关问题