53

如果字符串具有这种预测格式:

value = "hello and good morning"

其中 " (引号)也可能是 ' (单引号),并且结束字符(' 或 ")将与开始字符相同。我想匹配引号之间的字符串。

\bvalue\s*=\s*(["'])([^\1]*)\1

(两个 \s 允许 = 符号附近的任何空格)

第一个“捕获的组”(在第一对括号内) - 应该与应该是 ' 或 " 的开头引号匹配然后 - 我应该允许任何数量的字符不是第一组中捕获的字符,然后我期望在组中捕获的字符(括起来的引号)。

(所需的字符串应在第二个捕获组中捕获)。
但这不起作用。

这样做:

\bvalue\s*=\s*(['"])([^"']*)["']

但我想确保左引号和右引号(双引号或单引号)相同。


编辑
目标基本上是获取一个锚的开始标签,该锚的类属性中包含某个类名,我想涵盖类属性的罕见情况,包括 (') 或 (")。

遵循此处的所有建议,我使用了以下模式:

<\s*\ba\b[^<>]+\bclass\s*=\s*("|'|\\"|\\')(?:(?!\1).)*\s*classname\s*(?:(?!\1).)*\1[^>]*>

含义
找到一个标签打开的标志。
允许任何空格。
找到单词a。
允许任何非结束标签。
Find "class (any spaces) = (any spaces)"
获取开引号,以下之一:(" or ' or \" or \')。
来自 Alan Moore 的回答:允许任何不是开头引号的字符。
find classname
允许任何不是开头引号的字符。
找到与开头相同的结尾引号。
允许任何未关闭标签字符。
找到结束标记 char。

4

6 回答 6

76

您必须使用否定的前瞻,而不是否定的字符类:

\bvalue\s*=\s*(["'])(?:(?!\1).)*\1

(?:(?!\1).)*在前瞻确认该字符不是捕获组匹配的任何字符,一次消耗一个字符, (["'']). 一个字符类,无论是否否定,一次只能匹配一个字符。据正则表达式引擎所知,\1它可以表示任意数量的字符,并且没有办法说服\1它只包含"or'在这种情况下。因此,您必须使用更通用(且可读性更低)的解决方案。

于 2011-11-08T22:14:01.927 回答
2

您可以使用:

\bvalue\s*=\s*(['"])(.*?)\1

看见

于 2011-11-08T19:08:36.957 回答
2

在不知道您需要什么信息的情况下(或者甚至不知道您使用此正则表达式的语言或工具),我可以建议许多路径。

使用这些字符串:

value = "hello and good morning"
value = 'hola y buenos dias'
value = 'how can I say "goodbye" so soon?'
value = 'why didn\'t you say "hello" to me this morning?'
value = "Goodbye! Please don't forget to write!"
value = 'Goodbye! Please don\'t forget to write!'

这个表达式:

"((\\"|[^"])*)"|'((\\'|[^'])*)'

将匹配这些字符串:

"hello and good morning"
'hola y buenos dias'
'how can I say "goodbye" so soon?'
'why didn\'t you say "hello" to me this morning?'
"Goodbye! Please don't forget to write!"
'Goodbye! Please don\'t forget to write!'

当使用单个前置转义时,它将允许“其他”类型的引用或相同类型的引用\。引用字符串的内容在第 1 组或第 3 组中。您可以通过获取第一个(或最后一个)字符来确定使用哪种类型的引号。

如果您需要将其中一些内容放在特定的匹配组中,请提供更具体的示例(并包括不应该工作但看起来可能很接近的内容)

请询问您是否想走这条路线并需要更多帮助

于 2011-11-08T19:56:55.077 回答
1

回答这个问题如何在被忽略的集合中使用数字参考?

在这里,因为它被标记为与这个完全相同。

无法真正在类中指定捕获组。
可以做的是在否定断言中指定字符,像这样

(["'])((?:(?!\1)[\S\s])*)(\1)

展开

 ( ["'] )                      # (1)
 (                             # (2 start)
      (?:
           (?! \1 )
           [\S\s] 
      )*
 )                             # (2 end)
 ( \1 )                        # (3)

请注意,在原始帖子[^char]中通常也匹配换行符
,但由于这是 JavaScript(旧 JS),因此不能使用点。
改为使用[\S\s],它匹配任何字符。

于 2019-12-10T23:13:24.373 回答
0

当我们为 CMS Effcore 编写 Markdown 解析器时,我们尝试了不同的变体以确保尽可能高的速度。这些变体如下所示:

替换示例:

"markdown *text*"

到:

"markdown <em>text</em>"

字符“*”和“_”的 PHP 代码 #1(贪婪模式):

preg_replace('%'.'([*_])'.'(?<phrase>.+?)'.'\\1'.'%sS', '<em>$2<em>', $text);

字符“*”和“_”的 PHP 代码 #2(反向引用中的否定):

preg_replace('%'.'([*_])'.'(?<phrase>(?:(?!\\1).){1,})'.'\\1'.'%sS', '<em>$2<em>', $text);

单个字符“*”的 PHP 代码 #3(字符类中的否定):

preg_replace('%'.'([*])'.'(?<phrase>[^*]{1,})'.'[*]'.'%sS', '<em>$2<em>', $text);

案例#1(“贪婪模式”)比案例#2(“反向引用中的否定”)快。

测试了 1000000 次迭代:

  1. 0.0245740413665 秒。
  2. 3.3793921470642 秒。
于 2021-05-14T09:09:48.533 回答
0

我在寻找与我的模式匹配的帮助时遇到了这篇文章:

value="long text with \"quoted values\" and more"

Alan Moore 当前的最佳答案在这里非常好,但不考虑引用的转义。因此,由于 Alan 的所有功劳,您可以在允许使用以下命令转义引号时使用此模式\

\bvalue\s*=\s*(["'])(?:(?!(?<!\\)\1).)*\1

奖金信息

也许您在这里寻找的模式与我的目的相同,因此我也会分享我的最终解决方案。我必须匹配几个键值对,其格式与通常在节点中列出的 html 属性相同,例如:one="first" two="second".

以下正则表达式将与此匹配,并将捕获组命名keyvalue

\b(?P<key>[^=\s]*)\s*=\s*(["'])(?P<value>(?:(?!(?<!\\)\2).)*)\2
于 2021-07-12T12:52:09.257 回答