【问题标题】:Match fixed-width numbers with right-padded contiguous whitespace将固定宽度的数字与右填充的连续空白匹配
【发布时间】:2019-09-28 23:46:35
【问题描述】:

我正在尝试在更大的正则表达式和固定列文本块中验证格式。我想匹配一个固定宽度的模式,但前提是它左边只有数字,右边只有空格(或没有)。生成的表达式将在 python 中使用。

以下行应与 17 位模式匹配(标题除外):

MATCH
  *****************
A 20081122122332444 B
A 20081122122332    B
A 200811221223      B
A 2008112212        B
A 20081122          B

但以下不应该匹配

NO MATCH
  *****************
A 20081122112233 1  B
A 2008112211223 1   B
A 200811221     C   B
A 20081122 .        B

这个正则表达式很容易匹配有效数据:(?=\d+\s*)[\d\s]{17}

这似乎也提取了损坏的字符:(?=\d+[\s]?[^\d])[\d\s]{17}

由于位置不同,否定的后视将不起作用,我宁愿不重复该模式来处理字符串长度的所有可能变体。

似乎有一种优雅的方式可以在正则表达式中执行此操作 - 捕获一个连续的数字块,然后是一个连续的空格块,总共 17 个字符。

【问题讨论】:

  • 匹配0+个空格字符后右边有边界吗?例如,在 17 位数字或空格之后是否有规则?后面只能有非数字或空格吗?示例数据中 A 和 B 的含义是什么?列长是 18 吗?

标签: python regex fixed-width


【解决方案1】:

您的模式的部分问题在于您使用的是[\d\s]{17}。这将匹配 17 个字符的字符串,数字和空格的混合。虽然您想确保数字和空格(如果有)都是连续的。

为了限制字符串的长度,您可以使用正向 Lookahead 来验证整个字符串是否正好是 17 个字符。然后你匹配任意数量的数字(长度已经限制),可选地,后跟空白字符。

您可以使用以下模式:

^(?=.{17}$)\d+\s*?$

Demo.

【讨论】:

  • 这似乎取决于在行尾终止的模式。如果我在那里有其他字符(继续模式分别匹配),它现在匹配该行的一部分。尽管此修改可能有效:regex101.com/r/RWVe14/2
  • @interplanetary 不是。在这种模式中,前瞻实际上是多余的,无论如何都会匹配超过 17 个数字/空格。如果没有什么可以限制 17 个所需字符之前/之后的内容,我认为不会有仅使用正则表达式的解决方案(我可能是错的)。 但是,如果您知道链接中指出的之前和之后的内容,则可以改用以下内容:A\s(?=.{17}\sB)(\d+\s*?)\sB,您将在第一个捕获组中获得所需的 17 个字符( demo)。让我知道这是否适合您。
  • 由于 OP 想要在较大的正则表达式中匹配正则表达式,您应该删除 ^$ 锚点。但是问题仍然存在:(?=.{17}$)\d+\s*? 将不匹配 '1234567890 ' 中的空格,而 (?=.{17}$)\d+\s* 将匹配 '1234567890 ' 中的太多空格。 (我尝试在1234567890末尾添加额外的空格,但它们没有出现)
【解决方案2】:

您可以通过搜索数字来实现目标,然后是空格并计算 span 中的字符数 import re text="20081122 . "
if re.search('[\d]{1,}[\s]{0,}',s).span()[1]==17: print("yes") else print("no")

【讨论】:

    【解决方案3】:

    您说您正在寻找 17 个字符宽度的列,因此我最多只能匹配 17 个字符,因为不清楚这 17 个字符后面可以包含什么(可能是额外的空格,似乎是这种情况):

    import re
    
    text = """A 20081122122332444 B
    A 20081122122332    B
    A 200811221223      B
    A 2008112212        B
    A 20081122          B"""
    
    l = [m.group(0)[0:17] for m in re.finditer(r'\d+\s*', text) if m.span(0)[1] - m.span(0)[0] >= 17]
    
    print(l)
    

    打印:

    ['20081122122332444', '20081122122332   ', '200811221223     ', '2008112212       ', '20081122         ']
    

    如果您将它用作更大的正则表达式的一部分,那么也许我们必须假设 17 个字符的列后跟一个空格,然后我们有:

    (?=\d[\d\s]{16})\d+\s*(?=\s)
    

    【讨论】:

      猜你喜欢
      • 2012-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-04
      • 1970-01-01
      • 2012-01-12
      • 2013-04-09
      • 1970-01-01
      相关资源
      最近更新 更多