正则表达式字面上和被动地匹配换行符

问题描述

我必须构建一个匹配客户端代码的正则表达式,如下所示:

  • XXX/X{3,6}
  • XXX.X{3,6}/XXX

X 是一个介于 0 和 9 之间的数字。

正则表达式需要足够强大,这样我们就不会提取一个字符串中的代码。使用单词边界是我的第一个想法。 正则表达式如下所示:\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 demothis 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']

this Python demo

详情

  • (?<![^\s\n]) - 负向后视匹配一个位置,该位置之前没有紧跟一个除空格和 LF 字符以外的字符
  • (?<!\S(?<!\\n)) - 左空白边界,如果非空白是 n 字符组合中的 \n,则不会触发
  • \d{3} - 数字
  • [./] - ./
  • \d{3,6} - 三到六位数字
  • (?:/\d{3})? - / 和三位数字的可选序列
  • (?![^\s\n]) - 负向前瞻,除了紧邻当前位置右侧的空格和 LF 之外,不需要任何字符。
  • (?!(?!\\n)\S) - 右空白边界,如果非空白是 \ 字符后跟 n,则不会触发。