【问题标题】:Regex for a string with multpile test cases具有多个测试用例的字符串的正则表达式
【发布时间】:2021-04-16 12:13:19
【问题描述】:

我正在尝试找出可能导致不同格式的字符串的特定正则表达式:

例子:

"Fluid 13.4"

"Fluid 13.4 gm% fluid_haemo 12.0-14.0"

"Fluid gm% 13.4 fluid_haemo 12.0-14.0"

"Fluid gm% fluid_hameo 12.0-14.0 13.4"

"fluid fluid fluid 13.4"

"fluid rex cell (FRC) 13.4"

"Fluid rex cell 1800"

我的实际要求有点棘手:

  1. 我想要“流体”或字符串中的第一个单词。

  2. 数字“13.4”或在某些情况下可能不是小数。

  3. 如果字符串中有连续单词后跟小数或数字。

    字符串 1:“流体,13.4”编辑

    字符串 2:“流体 13.4”

    字符串 3:“流体 13.4”

    弦 4:流体 13.4"

    字符串 5:“流体流体 13.4”

    字符串 6:“流体雷克斯细胞 (FRC) 13.4”

    字符串 7:“流体雷克斯细胞 1800”

我尝试过的:

[a-zA-Z].* \d.*\.+\d.*

[a-zA-Z].* [\d.]+ (?=[a-z%\/])

但是由于显而易见的原因,我的正则表达式非常特定于大小写,我肯定不知道字符串会以什么格式生成。

有什么方法或正则表达式可以解决这样的问题吗?

【问题讨论】:

    标签: python python-3.x regex


    【解决方案1】:

    你可能会使用

    \b([a-zA-Z]+)(?: [a-zA-Z]+%.*?)? (\d+(?:\.\d+)?)(?!\S)
    
    • \b 防止部分匹配的单词边界
    • ([a-zA-Z]+)捕获组1,匹配1+ char a-zA-Z
    • (?: [a-zA-Z]+%.*?)? 可以选择匹配空格和字符 a-z,后跟 % 和空格
    • (\d+(?:\.\d+)?) 捕获第 2 组,匹配 1+ 位和可选的小数部分
    • (?!\S) 断言右边的空白边界

    Regex demo

    import re
    
    strings = [
        "Fluid 13.4",
        "Fluid 13.4 gm% fluid_haemo 12.0-14.0",
        "Fluid gm% 13.4 fluid_haemo 12.0-14.0",
        "Fluid gm% fluid_hameo 12.0-14.0 13.4"
    ]
    pattern=r"\b([a-zA-Z]+)(?: [a-zA-Z]+%.*?)? (\d+(?:\.\d+)?)(?!\S)"
    for s in strings:
        print(re.findall(pattern, s))
    

    输出

    [('Fluid', '13.4')]
    [('Fluid', '13.4')]
    [('Fluid', '13.4')]
    [('Fluid', '13.4')]
    

    编辑

    要捕获第一组中包含的“单词”,您可以选择包含重复匹配空格,后跟任何允许的字符的 1 倍以上,这些字符以右侧的空白边界结尾。

    \b([A-Za-z]+\b(?:\s+[\w()]+)*(?!\S)).*?\s(\d+(?:\.\d+)?)(?!\S)
    
    • \b防止部分匹配的单词边界
    • ( 捕获第 1 组
      • [A-Za-z]+\b 匹配 1+ 个字符 A-Za-z 和一个单词边界
      • (?:\s+[\w()]+)* 可选地重复空白字符,后跟字符类中任何允许字符的 1 倍以上
      • (?!\S) 断言右边的空白边界
    • )关闭第一组
    • .*?\s 匹配尽可能少的字符,然后是空格字符
    • ( 捕获第 2 组
      • \d+(?:\.\d+)?
    • )关闭第二组
    • (?!\S) 断言右边的空白边界

    Regex demo

    【讨论】:

    • 我怀疑应该是\b([A-Za-z]+)\b.*?\s(\d+(?:\.\d+)?)(?!\S)。刚想出这个,因为我认为所有字符串都应该匹配。
    • 对于 3 号和 4 号测试用例,它并没有真正奏效。
    • @WiktorStribiżew 啊,我明白了,我错过了那部分。我用可选部分更新了它。
    • @WiktorStribiżew 你当然可以发布那个:-)
    • @JimitVaghela 是的,我添加了示例代码来获取组值。如果% 部分不是强制性的,您也可以查看 Wiktor 的答案。
    【解决方案2】:

    你可以使用

    import re
    rx = r'\b([A-Za-z]+)\b.*?\s(\d+(?:\.\d+)?)(?!\S)'
    texts = ["Fluid 13.4","Fluid 13.4 gm% fluid_haemo 12.0-14.0","Fluid gm% 13.4 fluid_haemo 12.0-14.0","Fluid gm% fluid_hameo 12.0-14.0 13.4"]
    for text in texts:
        match = re.search(rx, text)
        if match:
            print(text, '=>', f'{match.group(1)} {match.group(2)}')
    
    # => Fluid 13.4 => Fluid 13.4
    #    Fluid 13.4 gm% fluid_haemo 12.0-14.0 => Fluid 13.4
    #    Fluid gm% 13.4 fluid_haemo 12.0-14.0 => Fluid 13.4
    #    Fluid gm% fluid_hameo 12.0-14.0 13.4 => Fluid 13.4
    

    请参阅 Python demoregex demo

    详情

    • \b - 单词边界
    • ([A-Za-z]+) - 第 1 组:一个 ASCII 字母词
    • \b - 单词边界
    • .*? - 除换行符以外的任何零个或多个字符,尽可能少
    • \s - 一个空格
    • (\d+(?:\.\d+)?) - 第 2 组:一位或多位数字,然后是 . 和一位或多位数字的可选序列
    • (?!\S) - 右侧空白边界。

    【讨论】:

    • 肯定不错 ++
    • 嗨,我添加了两个新的测试字符串。对此的任何建议将不胜感激。
    • @JimitVaghela 我的解决方案works
    • 它确实捕获了“fluid”和“13.4”,但假设在我最近添加的最后两个字符串中,在该部分中,我还想匹配所有存在的单词作为数字?
    • @JimitVaghela 所以,你想要\b([A-Za-z]+\b.*?)\s+(\d+(?:\.\d+)?)(?!\S)?见this demo
    【解决方案3】:

    看起来你的输入总是有Fluid,然后后面的第一个数字就是你想要的。如果是这种情况,您可以使用

    Fluid\b.*?(\d*\.?\d*)
    

    这匹配文本Fluid,后跟一个“边界”字符,然后跳过它可以找到的最小字符数,直到找到尽可能多的十进制数字字符,可选的小数点后跟尽可能多的十进制字符可以的。

    这当然是特定于您的情况,并且依赖于 Fluid 始终存在。

    在您的最后一种情况下,它将匹配 12.0 而不是 13.4

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-01
      相关资源
      最近更新 更多