【问题标题】:Python Regex Engine - "look-behind requires fixed-width pattern" ErrorPython 正则表达式引擎 - “后视需要固定宽度的模式”错误
【发布时间】:2021-02-21 23:59:09
【问题描述】:

我正在尝试处理 CSV 格式的字符串中不匹配的双引号。

准确地说,

"It "does "not "make "sense", Well, "Does "it"

应该改正为

"It" "does" "not" "make" "sense", Well, "Does" "it"

所以基本上我想做的是

替换所有的'"'

  1. 前面没有行首或逗号 (and)
  2. 后面没有逗号或行尾

用'""'

为此,我使用以下正则表达式

(?<!^|,)"(?!,|$)

问题是当 Ruby 正则表达式引擎 (http://www.rubular.com/) 能够解析正则表达式时,python 正则表达式引擎 (https://pythex.org/, http://www.pyregex.com/) 会抛出以下错误

Invalid regular expression: look-behind requires fixed-width pattern

而使用 python 2.7.3 它会抛出

sre_constants.error: look-behind requires fixed-width pattern

谁能告诉我这里的python有什么烦恼?

================================================ ====================================

编辑:

在蒂姆的回复之后,我得到了以下多行字符串的输出

>>> str = """ "It "does "not "make "sense", Well, "Does "it"
... "It "does "not "make "sense", Well, "Does "it"
... "It "does "not "make "sense", Well, "Does "it"
... "It "does "not "make "sense", Well, "Does "it" """
>>> re.sub(r'\b\s*"(?!,|$)', '" "', str)
' "It" "does" "not" "make" "sense", Well, "Does" "it" "\n"It" "does" "not" "make" "sense", Well, "Does" "it" "\n"It" "does" "not" "make" "sense", Well, "Does" "it" "\n"It" "does" "not" "make" "sense", Well, "Does" "it" " '

在每一行的末尾,在 'it' 旁边添加了两个双引号。

所以我对正则表达式做了一个很小的改动来处理换行符。

re.sub(r'\b\s*"(?!,|$)', '" "', str,flags=re.MULTILINE)

但这给出了输出

>>> re.sub(r'\b\s*"(?!,|$)', '" "', str,flags=re.MULTILINE)
' "It" "does" "not" "make" "sense", Well, "Does" "it"\n... "It" "does" "not" "make" "sense", Well, "Does" "it"\n... "It" "does" "not" "make" "sense", Well, "Does" "it"\n... "It" "does" "not" "make" "sense", Well, "Does" "it" " '

最后一个 'it' 单独有两个双引号。

但我想知道为什么'$'行尾字符不能识别行已结束。

================================================ ====================================

最终的答案是

re.sub(r'\b\s*"(?!,|[ \t]*$)', '" "', str,flags=re.MULTILINE)

【问题讨论】:

  • Python lookbehind 断言的长度必须是恒定的,并且 (?

标签: python regex


【解决方案1】:

Python relookbehinds 确实需要固定宽度,当您在后视模式中有不同长度的交替时,有几种方法可以处理这种情况:

  • 重写模式,这样您就不必使用交替(例如,蒂姆的上述答案使用单词边界,或者您也可以使用与当前模式完全等效的(?&lt;=[^,])"(?!,|$),在双引号,或匹配用空格括起来的单词的常见模式,(?&lt;=\s|^)\w+(?=\s|$),可以写成(?&lt;!\S)\w+(?!\S)),或者
  • 拆分lookbehinds:
    • 需要在一个组中交替使用正向lookbehinds(例如,(?&lt;=a|bc) 应重写为(?:(?&lt;=a)|(?&lt;=bc))
    • 可以只串联否定的lookbehinds(例如(?&lt;!^|,)"(?!,|$) 应该看起来像(?&lt;!^)(?&lt;!,)"(?!,|$))。

或者,只需使用pip install regex(或pip3 install regex)安装PyPi regex module,即可享受无限宽度的后视。

【讨论】:

  • 为什么你认为我们需要(?:(?&lt;=a)|(?&lt;=bc)) 中的额外?:,为什么(?&lt;=a)|(?&lt;=bc) 不够好?顺便说一句,答案很好
  • @user1993 如果您打算将其添加到另一个更大的模式中,则必须进行分组。否则,lookbehinds 将不会应用于后续模式,模式将被破坏。如果您需要按原样使用(?&lt;=a)|(?&lt;=bc),作为独立模式,是的,不需要分组。
  • (?: (?
【解决方案2】:

Python lookbehind assertions 需要固定宽度,但你可以试试这个:

>>> s = '"It "does "not "make "sense", Well, "Does "it"'
>>> re.sub(r'\b\s*"(?!,|$)', '" "', s)
'"It" "does" "not" "make" "sense", Well, "Does" "it"'

解释:

\b      # Start the match at the end of a "word"
\s*     # Match optional whitespace
"       # Match a quote
(?!,|$) # unless it's followed by a comma or end of string

【讨论】:

  • look-behind assertions need to be fixed width 这仅特定于 python 吗?或者它是一个通用约束
  • 据我所知,Python、Perl 和 Boost 库都需要固定长度的后视。一些正则表达式风格根本不支持后视,一些允许可变但有限的长度,还有一些没有限制。
猜你喜欢
  • 1970-01-01
  • 2014-07-09
  • 2018-01-10
  • 1970-01-01
  • 2018-01-02
  • 2020-02-07
  • 1970-01-01
  • 2017-08-17
相关资源
最近更新 更多