【问题标题】:Python re.search for multiple values in the same linePython re.search 在同一行中搜索多个值
【发布时间】:2021-09-21 12:25:53
【问题描述】:

我正在尝试使用 re.search(或 re.findall)来解释一行,并将关键字更改为一个值。

我的示例字符串是:

line = 'Text1 <<ALTER, variable = Ion1>> Text2 <<ALTER, variable = Value1>>\n'

'Na' 的 Ion1 和 1.0 的 Value1 的值,我想要返回

processedline = 'Text1 Na Text2 1.0'

为此,我尝试了以下代码:

result = re.search('<<ALTER(.*)>>', line)
aux_txt = result.group(1).split('=')
var = aux_txt[-1].strip()
value = ParameterDictionary[var]
processedline = re.sub('<<ALTER(.*)>>', str(value), line, flags=re.DOTALL)

但是,对于变量result,我得到的返回是', variable = Ion1&gt;&gt; Text2 &lt;&lt;ALTER, variable = Value1',即它不会独立处理两个关键字。

有人有什么想法吗?提前致谢!

【问题讨论】:

标签: python regex string python-re


【解决方案1】:

这是因为您的正则表达式匹配整个字符串(直到最后一个 &gt;&gt;),而不是匹配直到 &gt;&gt;Ion1 之后的第一次出现。您需要使用 lazy 运算符和 .* 来限制匹配。

.*? 的作用是:它匹配前一个令牌在零次到无限次之间,尽可能少,根据需要扩展(惰性)

这是一个带有解释的示例:https://regex101.com/r/oKyOIn/1

【讨论】:

    【解决方案2】:

    Python re.search 同一行中的多个值

    re.search 是执行此任务的错误工具,它确实返回第一个(最左侧)匹配项,如果未找到匹配项,则返回 None。您应该使用re.finditer 提供匹配对象的迭代器或re.findall 提供strs 或listlisttuples。

    同样如前所述,您需要更改您的模式 &lt;&lt;ALTER(.*)&gt;&gt;,因为它确实匹配太多,您可能会使用非贪婪版本,即

    <<ALTER(.*?)>>
    

    或者如果&gt; 不允许在&lt;&lt;&gt;&gt; 内使用,则如下所示

    <<ALTER([^>]*)>>
    

    【讨论】:

      【解决方案3】:

      您需要在&lt;&lt;ALTER, variable =&gt;&gt; 中捕获一个或多个单词字符(包括下划线的字母数字),然后在re.sub 方法替换参数中使用可调用函数:

      Python demo

      import re
      ParameterDictionary = {'Ion1': 'Na', 'Value1': '1.0'}
      line = 'Text1 <<ALTER, variable = Ion1>> Text2 <<ALTER, variable = Value1>>\n'
      rx = r'<<ALTER, variable = (\w+)>>'
      result = re.sub(rx, lambda x: ParameterDictionary.get(x.group(1), x.group()), line)
      print(result)
      # => Text1 Na Text2 1.0
      

      这里,

      • &lt;&lt;ALTER, variable = (\w+)&gt;&gt; 匹配 &lt;&lt;ALTER, variable =、空格,然后 (\w+) 将任何一个或多个单词字符捕获到第 1 组,然后匹配 &gt;&gt;
      • 匹配被传递到 lambda 表达式中的 re.sub,如 xParameterDictionary.get(x.group(1), x.group()) 要么通过找到的键返回相应的值,要么返回整个匹配 (x.group())。

      【讨论】:

        【解决方案4】:

        使用组在re.sub 中捕获似乎是您正在寻找的。 re.sub 接受一个函数作为 repl(替换字符串参数)。该函数使用匹配对象作为参数进行评估。见docs

        >>> param_dict = {'Ion1': 'Na', 'Variable1': '1.0'}
        >>> re.sub(r'<<ALTER, variable = ([\w\d]+)>>', lambda m: param_dict[m.group(1)], line)
        'Text1 Na Text2 1.0\n'
        

        正则表达式组([\w\d]+) 可以适应您希望找到的值类型。

        在 python 中对正则表达式使用原始字符串(以 r' 开头)是一种很好的做法,可以让您免于头痛。

        【讨论】:

        • 已编辑以替换为字典中的值。 re.sub 接受一个函数作为 repl 参数。
        【解决方案5】:

        使用.* 过于宽泛,会捕获&lt;&lt;ALTER&gt;&gt; 之间的所有内容。为什么不使用更具体的正则表达式?

        >>> re.findall(r"<<ALTER, variable = (\w+)>>", line)
        ['Ion1', 'Value1']
        

        【讨论】:

        • OP 不需要提取匹配项,而是用字典中的值替换它们。见this solution
        【解决方案6】:

        非常感谢! 它像这样完美地工作:

        import re
        
        ParameterDictionary = {'Ion1': 'Na', 'Value1': '1.0'}
        line = 'Text1 <<ALTER, variable = Ion1>> Text2 <<ALTER, variable = Value1>>\n'
        result = re.findall(r'<<ALTER, variable = (\w+)>>', line)
        for txt in result:
            aux_txt = f'<<ALTER, variable = {txt}>>'
            value = ParameterDictionary[txt]
            line = re.sub(aux_txt, str(value), line, flags=re.DOTALL)
        

        【讨论】:

        • 没有必要执行这么多的正则表达式搜索。您只需要一次调用re.sub 并使用正则表达式解析文本一次,请参阅my answer
        猜你喜欢
        • 2013-09-02
        • 1970-01-01
        • 1970-01-01
        • 2013-04-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-10
        • 2018-01-16
        相关资源
        最近更新 更多