问题描述
- XXX/X{3,6}
- XXX.X{3,6}/XXX
正则表达式需要足够强大,这样我们就不会提取另一个字符串中的代码。使用单词边界是我的第一个想法。
正则表达式如下所示:\b\d{3}[\.\/]\d{3,6}(?:\/\d{3})?\b
单词边界的问题在于它也匹配点。因此,像“123/456.12”这样的数字将匹配“123/456”作为客户端号码。于是我想出了以下正则表达式:(?<!\S)\d{3}[\.\/]\d{3,6}(?:\/\d{3})?(?!\S)
。它使用后视和前视并检查该字符是否为空白。这与大多数客户端代码正确匹配。
但是还有最后一个问题。我们正在使用 Google OCR 文本从中提取代码。这意味着可以在 123/456\n
、\n123/456
、\n123/456\n
等文本中找到有效代码。检查前一个和/或下一个字符是否为空格不起作用,因为文字“\n”不包括在此。如果我将 (?<!\S|\\n)
之类的内容作为单词边界,它还会出于某种原因包含反斜杠和/或正斜杠。目前我想出了以下正则表达式 (?<![^\r\n\t\f\v n])\d{3}[\.\/]\d{3,6}(?:\/\d{3})?(?![^\r\n\t\f\v \\])
,但它只检查前一个字符是“n”还是空格,下一个是反斜杠或空格。所以像 "lorem\123/456" 这样的字符串仍然会找到匹配项。我需要一些方法来在空白字符中包含“\n”而不破坏前瞻/后视。
你们知道如何解决这个问题吗?感谢所有输入。谢谢!
解决方法
您似乎想从空白边界中减去 \n
。你可以使用
re.findall(r'(?<![^\s\n])\d{3}[./]\d{3,6}(?:/\d{3})?(?![^\s\n])',text)
参见 Python demo 和 this regex demo。
如果 \n
是 \
和 n
字符的组合,您需要确保环视中的 \S
不匹配那些:
import re
text = r'Codes like 123/456\n \n123/3456 \n123/23456\n etc are correct \n333.3333/333\n'
print( re.findall(r'(?<!\S(?<!\\n))\d{3}[./]\d{3,6}(?:/\d{3})?(?!(?!\\n)\S)',text) )
# => ['123/456','123/3456','123/23456','333.3333/333']
详情:
-
(?<![^\s\n])
- 负向后视匹配一个位置,该位置之前没有紧跟一个除空格和 LF 字符以外的字符 -
(?<!\S(?<!\\n))
- 左空白边界,如果非空白是n
字符组合中的\n
,则不会触发 -
\d{3}
- 数字 -
[./]
-.
或/
-
\d{3,6}
- 三到六位数字 -
(?:/\d{3})?
-/
和三位数字的可选序列 -
(?![^\s\n])
- 负向前瞻,除了紧邻当前位置右侧的空格和 LF 之外,不需要任何字符。 -
(?!(?!\\n)\S)
- 右空白边界,如果非空白是\
字符后跟n
,则不会触发。