【问题标题】:Regular expression unexpected behavior正则表达式意外行为
【发布时间】:2016-03-17 00:46:05
【问题描述】:

我正在开发一个函数,它可以用给定的规则翻译给定的文本。

def bork(text):
    """
    Implementation of language transformation based on Swedish-Chef talk.
    """

    rules = {"\be": "i",
        "the": "zee",
        "\Be\b": "e-a",
        "an": "un"
        }

    rules = dict((re.escape(k), v) for k, v in rules.items())
    pattern = re.compile("|".join(rules.keys()))
    borked = pattern.sub(lambda i: rules[re.escape(i.group(0))], text.strip())
    return borked

text = """experienced"""
print bork(text)
# gives "experienced"

它应该在哪里提供"ixperienced"。因为规则\be: i。其他转换在使用较大输入进行测试时效果很好,但失败了,请帮助我。

编辑:我添加了规则"\Bi\B": "ee"。结果应该是"ixpereeenced"。这也没有奏效。我仍然收到"experienced"

Edit2:似乎问题存在于我使用反斜杠的规则中,但是,我尝试使用原始字符串和re.escape()。之后,我尝试删除re.escape(),但这给了我字典调用中的一个关键错误。(我也想知道为什么会发生这种情况)

【问题讨论】:

    标签: python regex python-2.7 python-3.x


    【解决方案1】:

    "\b" 是退格字符,ASCII 值为 8。r"\b" 是文字字符 \b。使用原始字符串来防止转义序列被解释。

    rules = {
        r"\be": "i",
        r"the": "zee",
        r"\Be\b": "e-a",
        r"an": "un"
    }
    

    然后,摆脱第一个re.escape() 调用。

    【讨论】:

    • 摆脱 re.escape() 调用使我在这种情况下遇到关键错误。也许如果你能帮我解决我的问题:(
    • @Rockybilly 问题是当正则表达式包含像\b 这样的特殊正则表达式结构时,匹配的文本将不等于正则表达式。因此,您无法使用匹配的文本索引到规则字典。
    • @pasztorpisti 那么没有其他方法可以做到这一点吗?我以这种方式编写代码是因为我想同时进行所有转换(一次运行)。否则重叠模式会产生错误的答案,例如将同一个字母转换两次。
    • 至少不容易 - 使用您现在使用的正则表达式,匹配对象无法知道例如它在词首 e -> i case 或词尾 e -> e-a case
    【解决方案2】:

    一次 re.sub,使用捕获组,以便我们可以确定 哪个模式在相关区域上匹配。您可以通过保留模式列表来简化 subst 函数的逻辑,而不必每次都枚举 rules 字典...

    rules = {
        r'(\be)'   : 'i',
        r'(the)'   : 'zee',
        r'(an)'    : 'un',
        r'(\Be\b)' : 'e-a'
    }
    pattern = '|'.join(rules.iterkeys())
    
    def subst(matchobj):
        dind = [ind for (ind, val) in enumerate(matchobj.groups()) if val is not None][0]
        return rules[[val for (ind, val) in enumerate(rules) if ind == dind][0]]
    
    text = 'experienced'
    re.sub(pattern, subst, text)
    

    【讨论】:

      【解决方案3】:

      正则表达式组的顺序很重要。使用“|”时,即使列表中有更长的匹配项,也接受第一个匹配项。所以你不应该依赖dict.keys(),因为订单是未定义的。使用列表(我猜你可以使用有序字典)。此外,matchobject.lastindex 返回最后一个(或唯一一个)匹配组的索引。

      rules = [ 
          (r'\be'  , 'i'  ),
          (r'the'  , 'zee'),
          (r'an'   , 'un' ),
          (r'\Bi\B', 'ee' ),
          (r'\Be\b', 'e-a'  )
      ]
      
      pattern = '|'.join('({})'.format(rule[0]) for rule in rules)
      
      def subst(matchobj):
          #print(matchobj)
          return rules[matchobj.lastindex-1][1]
      
      text = 'experienced'
      re.sub(pattern, subst, text)
      

      返回:

      'ixpereeenced'
      

      【讨论】:

      • 那么一次运行多次更改的方法是什么?将较长的匹配项放在规则列表的末尾?还是相反?
      • 一般情况下,较长的匹配应该先出现。例如,在模式“a|ab”中,“ab”永远不会匹配,因为“a”将首先匹配——结束搜索。但是如果模式反转为“ab|a”,“ab”可以匹配。可能更难确定模式中何时存在可选或重复部分(例如,使用 *、+、? 等)。
      猜你喜欢
      • 2012-07-16
      • 2013-01-14
      • 1970-01-01
      • 1970-01-01
      • 2013-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-06
      相关资源
      最近更新 更多