【问题标题】:regex or does not work - I do not know what is wrong in my pattern正则表达式或不起作用 - 我不知道我的模式有什么问题
【发布时间】:2020-11-08 10:13:53
【问题描述】:

我有以下字符串:

2020-10-2125Chavez and Sons
2020-05-02Bean Inc
NaNRobinson, Mcmahon and Atkins
2020-04-25Hill-Fisher
2020-04-02Nothing and Sons
52457Carpenter and Sons
0Carpenter and Sons
Carpenter and Sons
NoneEconomy and Sons
2020-04-02

我想把它分开:

myRegex = '^([-\d]{0,}|[NnaAOoEe]{0,})(.*)' or '^([0-9]{4}-[0-9]{2}-[0-9]{2,}|[\d]{0,}|[NnaAOoEe]{0,})([\D]{0,})$'

我想要所有数字,完全匹配 (na, nan, none) - 大写和小写以及第一组中的“”,例如:

[2020-10-2125][Chavez and Sons]
[2020-05-02][Bean Inc]
[NaN][Robinson, Mcmahon and Atkins]
[2020-04-25][Hill-Fisher]
[2020-04-02][Nothing and Sons]
[52457][Carpenter and Sons]
[0][Carpenter and Sons]
[][Carpenter and Sons]
[None][Economy and Sons]
[2020-04-02][]

这是错误的:

[2020-04-02No][thing and Sons]

我想要

[2020-04-02][Nothing and Sons]

如何编写一个正则表达式来检查“无”之类的完全匹配 - 不区分大小写(也应该识别“无”、“nOne”等)?

https://regex101.com/r/HvnZ47/3

【问题讨论】:

  • 您可以为整个正则表达式设置 re.IGNORECASE 标志或匹配例如[Nn][Oo][Nn][Ee] 表示“无”。
  • thx 我怎样才能将它与另一个结合起来?
  • 在括号中你可以或|可能的匹配一起。

标签: python regex


【解决方案1】:

re.I 的以下情况如何:

(None|NaN?|[-\d]+)?(.*)

https://regex101.com/r/d4XPPb/3

解释:

  • (None|NaN?|[-\d]+)?
    • 要么没有
    • 或者最后一个 N 是可选的 NaN(由于 ?)所以它也匹配 NA
    • 或数字和破折号一次或多次
    • 整个组 () 是可选的,因为 ? 这意味着它可能不存在
  • (.*) 任何字符到最后

但是,仍然可能存在边缘情况。考虑以下几点:

National Geographic
---Test

会被解析为

[Na][tional Geographic]
[---][Test]

另一种选择:

从这里我们可以继续使正则表达式变得更复杂,但是,我认为在没有正则表达式的情况下实现自定义解析会简单得多。每行循环字符和​​:

  • 如果它以数字开头,则将所有数字和破折号解析到第 1 组,其余在第 2 组(即当您点击一个字符时,更改组)
  • 获取字符串的前 4 个字符,如果它们是“无”,则将它们分开。同时确保第5个字符为大写(不区分大小写line[:4].lower() == "none" and line[4].isupper()
  • 与上述步骤类似,但对于 NA 和 NaN:
    • line[:3].lower() == "nan" and line[3].isupper()
    • line[:2].lower() == "na" and line[2].isupper()

以上应该会产生更准确的结果,并且应该更容易阅读。

示例代码:

with open("/tmp/data") as f:
    lines = f.readlines()

results = []
for line in lines:
    # Remove spaces and \n
    line = line.strip()
    if line[0].isdigit() or line[0] == "-":
        i = 0
        while line[i].isdigit() or line[i] == "-":
            i += 1
            if i == len(line) - 1:
                i = len(line)
                break
        results.append((line[:i], line[i:]))

    elif line[:4].lower() == "none" and line[4].isupper():
        results.append((line[:4], line[4:]))

    elif line[:3].lower() == "nan" and line[3].isupper():
        results.append((line[:3], line[3:]))

    elif line[:2].lower() == "na" and line[2].isupper():
        results.append((line[:2], line[2:]))
    else:
         # Assume group1 is missing! Everything is group2
         results.append((None, line))

for g1, g2 in results:
    print(f"[{g1 or ''}][{g2}]")

数据:

$ cat /tmp/data 
2020-10-2125Chavez and Sons
2020-05-02Bean Inc
NaNRobinson, Mcmahon and Atkins
2020-04-25Hill-Fisher
2020-04-02Nothing and Sons
52457Carpenter and Sons
0Carpenter and Sons
Carpenter and Sons
NoneEconomy and Sons
NoNeEconomy and Sons
2020-04-02
NAEconomy and Sons
---Test
National Geographic

输出:

$ python ~/tmp/so.py 
[2020-10-2125][Chavez and Sons]
[2020-05-02][Bean Inc]
[NaN][Robinson, Mcmahon and Atkins]
[2020-04-25][Hill-Fisher]
[2020-04-02][Nothing and Sons]
[52457][Carpenter and Sons]
[0][Carpenter and Sons]
[][Carpenter and Sons]
[None][Economy and Sons]
[NoNe][Economy and Sons]
[2020-04-02][]
[NA][Economy and Sons]
[---][Test]
[][National Geographic]

【讨论】:

    【解决方案2】:

    您可以将要匹配的表达式与简单的| 组合在一起,但请记住,引擎将始终优先选择第一个可能的匹配项;所以你想把更具体的模式放在第一位,然后再回到更通用的情况。

    试试这个:

    my_re = re.compile(r'^([0-9]{4}-[0-9]{2}-[0-9]{2,}|\d+|N(?:aN|one)|)(\D.*)$', re.IGNORECASE)
    

    re.IGNORECASE 标志表示忽略大小写差异。

    另外,请注意量词{0,} 最好写成*;但是您希望至少需要一次匹配,或者回退到更通用的模式,所以实际上您想要+(也可以写成{1,};但同样,更喜欢更简洁的标准表示法)。 \D 周围不需要方括号,它已经封装了一个字符类(但如果你想合并两个字符类,比如[-\d],你确实需要方括号)。

    演示:https://ideone.com/Qwp5ao

    最后,请注意,用于命名局部变量的标准 Python 表示法更喜欢 snake_case 而不是 dromedaryCase。 (另见Wikipedia。)

    【讨论】:

      猜你喜欢
      • 2022-01-10
      • 2020-04-02
      • 2020-03-24
      • 2012-11-17
      • 2013-09-13
      相关资源
      最近更新 更多