【问题标题】:Python Regex - Match a character without consuming itPython Regex - 匹配一个字符而不使用它
【发布时间】:2013-11-21 10:20:03
【问题描述】:

我想转换下面的字符串

"For "The" Win","Way "To" Go"

"For ""The"" Win","Way ""To"" Go"

简单的正则表达式是

str2 = re.sub(r'(?<!,|^)"(?=\w)|(?<=\w)"(?!,|$)', '""', str1,flags=re.MULTILINE)

即双引号

  1. 后跟一个字母,但前面没有逗号或行首
  2. 前面有一个字母,后面没有逗号或行尾

问题是我使用的是 python,它的正则表达式引擎不允许在后向构造中使用 OR 运算符。我得到了错误

sre_constants.error:look-behind 需要固定宽度的模式

我正在寻找的是一个正则表达式,它将用'""' 替换'The' 和'To' 周围的'"'。 我可以使用以下正则表达式(提供给another question 的答案)

\b\s*"(?!,|[ \t]*$)

但这会占用“The”和“To”之前的空间,我得到以下内容

"For""The"" Win","Way""To"" Go"

是否有一种解决方法,以便我可以将“The”和“To”周围的引号加倍,而不会占用它们前面的空格?

【问题讨论】:

  • 对于这样的字符串:"For "The" mar"vel"ous Win",要不要修改名词内的引号?

标签: python regex


【解决方案1】:

不要说前面没有逗号或行首,而是说前面有一个非逗号字符:

r'(?<=[^,])"(?=\w)|(?<=\w)"(?!,|$)'

【讨论】:

  • 如果使用否定,那么我想我必须找到我必须否定的所有可能的字符。例如:r'(?
  • @SpikETidE,这不会产生所需的输出吗?
  • @SpikETidE 请把部分代码放在左边的两个字符` `和右边的两个字符` `之间。点击评论窗口右侧的帮助
  • @perreal :它适用于我在之前评论中提到的修改。
【解决方案2】:

在我看来你不需要为锚而烦恼。

  • 如果引号前有一个字符,您就知道它不在字符串的开头。
  • 如果该字符不是换行符,则说明您不在行首。
  • 如果字符不是逗号,则您不在字段的开头。

因此您不需要使用锚点,只需对单个字符进行积极的后视/前瞻:

result = re.sub(r'(?<=[^",\r\n])"(?=[^,"\r\n])', '""', subject)

我投了",因为可能有一些引号已经被转义了。但实际上,如果是这样的话,你可能还是被搞砸了。 ;)

【讨论】:

  • 唉,OP 是那种即使问错了问题也会等待好答案的人。请参阅我在 Markus 答案中的评论。
  • 这个方案的问题是"For "The" " hourrah!" Win"改成"For ""The"" "" hourrah!"" Win",而应该改成"For ""The"" " hourrah!" Win";如果OP问题中的条件(?=\w)(?&lt;=\w)真的是他想要的,我不确定。
  • 我认为 OP 将他的想法限制在一个具体的例子上,他需要转义的引号总是恰好在字母旁边,他让那个细节妨碍了他。我的态度是,我们来这里不是为了回答问题,而是为了帮助人们找到要问的正确问题。但是,正如您在第一条评论中所观察到的,并非每个人都有相同的感受。
  • “我们在这里不是为了回答问题,而是为了帮助人们找到正确的问题要问” 这取决于某人愿意付出的努力程度帮助别人。我承认,当问题写得如此糟糕时,这令人失望。我担心我不应该对主要练习 PHP 的 OP 感到失望,因为 PHP 不是一种严格教育...
【解决方案3】:
re.sub(r'\b(\s*)"(?!,|[ \t]*$)', r'\1""', s)

【讨论】:

  • @SpikETidE 因此,'(?&lt;!,|^)"(?=\w)|(?&lt;=\w)"(?!,|$)' 不是直接的正则表达式模式,如果 Python 具有可变长度的后向断言,并且条件 not preceded by a comma or the beginning of linenot followed by a comma or the end of line 不是真实的条件,你写的例子不是很好的例子,经过 4 年的会员资格和 49 个问题在 SO 上形成你,你总是不知道要问一个问题。被误会的不止我一个,因为除了马库斯以外的所有回答者都和我一样。
【解决方案4】:

遇到此问题时最直接的解决方法:将后视分解为两个后视。

str2 = re.sub(r'(?<!,)(?<!^)"(?=\w)|(?<=\w)"(?!,|$)', '""', str1,flags=re.MULTILINE)

(不要给你的字符串命名str

【讨论】:

  • @SpikETidE 也许再试一次?我刚刚测试过,它工作正常。理所当然 - 这两个后向断言在逻辑上是等价的。
  • @roippi:对不起。我的测试字符串存在差异,导致它失败。在您发布回复之前,我删除了我的评论。
【解决方案5】:
str2 = re.sub('(?<=[^,])"(?=\w)'
              '|'
              '(?<=\w)"(?!,|$)',

              '""',  ss,
              flags=re.MULTILINE)

我总是想知道为什么人们在不需要时使用原始字符串作为正则表达式模式。

请注意,我将您的 str(内置类的名称)更改为 ss

.

为了“有趣”:

str2 = re.sub('"'
              '('
              '(?<=[^,]")(?=\w)'
              '|'
              '(?<=\w")(?!,|$)'
              ')',

              '""', ss,
              flags=re.MULTILINE)

也可以

str2 = re.sub('(?<=[^,]")(?=\w)'
              '|'
              '(?<=\w")(?!,|$)',

              '"',  ss,
              flags=re.MULTILINE)

【讨论】:

  • 如果没有r,字符串将作为普通字符串处理,带有字符串转义。正则表达式中的某些转义在非原始字符串文字中具有不同的含义(\1\b 是两个示例)。与其根据您是否使用这些字符串来调整字符串的“原始性”,不如始终将r 放在正则表达式上。
  • 我知道,我知道。就个人而言,由于我使用的正则表达式模式与\1\b 一起使用的频率较低,因此我不喜欢将r 放在我更频繁使用的所有正则表达式模式前面,而是写\\1 \\2\\b必要时。顺便说一句,如果不是在原始字符串中,我们必须写 \\b 是一件奇怪的事情,而 \d \w \s etc 不需要相同的。我不知道是否还有其他特殊序列而不是您引用的序列需要在非原始字符串中使用双斜杠或在原始字符串中才能正常工作。你呢?
  • @Markus 事实上,奇怪的是,在字符串中也选择了基于字母b 的转义来表示退格,就像在正则表达式模式中表示边界一样。那么使'\r''\\r' 在非原始字符串正则表达式模式中等效的原理不能应用于b 的转义:在正则表达式模式中,非原始字符串'\b' 表示退格和'\\b' 以非原始字符串模式或r'\b' 表示边界。
  • 因此,非原始字符串正则表达式模式'(Mar.)\b' 是匹配'c:\Mary\yellow\Jimmy_and_Mari\bushka' 中的Mari 而不是Mary 的唯一方法
猜你喜欢
  • 2014-08-05
  • 2013-07-04
  • 2019-12-07
  • 2017-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-23
相关资源
最近更新 更多