正则表达式;反向引用字符集中不匹配的字符

Posted

技术标签:

【中文标题】正则表达式;反向引用字符集中不匹配的字符【英文标题】:Regex; backreferencing a character that was NOT matched in a character set 【发布时间】:2012-03-31 21:10:12 【问题描述】:

我想构造一个正则表达式,它匹配'",然后匹配其他字符,分别在匹配'" 时结束,具体取决于在开始时遇到的情况.所以这个问题看起来很简单,可以在最后使用反向引用来解决;下面是一些正则表达式代码(它在 Java 中,所以请注意额外的转义字符,例如 " 之前的 \):

private static String seekerTwo = "(['\"])([a-zA-Z])([a-zA-Z0-9():;/`\\=\\.\\,\\- ]+)(\\1)";

这段代码将成功处理诸如:

"hello my name is bob"
'i live in bethnal green'

当我有这样的字符串时,麻烦就来了:

"hello this seat 'may be taken' already"

使用上面的正则表达式会在遇到'时在初始部分失败,然后它会继续并成功匹配'may be taken'...但这显然是不够的,我需要匹配整个字符串。

我在想的是,我需要一种方法来忽略第一组中不匹配的引号类型,方法是将其作为字符包含在第三组的字符集中。但是,我知道没有办法做到这一点。是否有某种鬼鬼祟祟的 NOT 反向引用函数之类的?我可以用它来引用第一组中不匹配的字符??或者以其他方式解决我的困境?

【问题讨论】:

您好,欢迎来到 ***。我冒昧地重新格式化你的帖子。您可以单击编辑链接以查看我是如何做到的。知道您是否需要发布代码非常重要... 【参考方案1】:

这可以使用否定的lookahead assertions 来完成。以下解决方案甚至考虑到您可以在字符串中转义引号:

(["'])(?:\\.|(?!\1).)*\1

说明:

(["'])    # Match and remember a quote.
(?:       # Either match...
 \\.      # an escaped character
|         # or
 (?!\1)   # (unless that character is identical to the quote character in \1)
 .        # any character
)*        # any number of times.
\1        # Match the corresponding quote.

这与"hello this seat 'may be taken' already""hello this seat \"may be taken\" already" 正确匹配。

在 Java 中,带有所有反斜杠:

Pattern regex = Pattern.compile(
    "([\"'])   # Match and remember a quote.\n" +
    "(?:       # Either match...\n" +
    " \\\\.    # an escaped character\n" +
    "|         # or\n" +
    " (?!\\1)  # (unless that character is identical to the matched quote char)\n" +
    " .        # any character\n" +
    ")*        # any number of times.\n" +
    "\\1       # Match the corresponding quote", 
    Pattern.COMMENTS);

【讨论】:

Tim 的出色工作,感谢您编辑我的帖子。感谢您的建议,通过一些工作,我修改了我的代码: "(['\"])([a-zA-Z])((?!\\1)[a-zA-Z0-9 ():;/`'\"\\=\\.\\,\\- ])+(\\1)" 所以你的解决方案实际上很简单而且非常有效;在主要字符集之前添加正则表达式 if 语句的等效项,这将直接跳到最后一个循环。并将这两种类型的引号添加到主要字符集中。这样,如果在任何时候找到开始时找到的引号字符,正则表达式将终止并返回。不错。【参考方案2】:

如果您可以使用环视(Java 确实支持),Tim 的解决方案会非常有效。但是,如果您发现自己使用的语言或工具不支持环视,您可以简单地分别匹配两种情况(双引号字符串和单引号字符串):

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

分别匹配每种情况,但返回任一情况作为整个匹配项


但是

这两种情况都可能成为至少一种可能性的牺牲品。如果不仔细看,您可能会认为这段摘录中应该有 两个 匹配项:

他转身骑上他的自行车。 “等我做完这一切后再见。”他说,在开始他的旅程之前回头看了一会儿。当他进入街道时,一辆城市的手推车与迈克的自行车相撞。 “天啊!”旁观者惊呼。

...但是有 三个 匹配,而不是两个:

"I'll see you later, when I'm done with all this"
's trolleys collided with Mike'
"Oh my!"

而这段摘录只包含 一个 匹配项:

不过,战斗还没有结束。 “嘿!”鲍勃喊道。 “你想要什么?”我反驳道。 “你让我恶心!” “我为什么要关心?” “因为我爱你!” “你做?” Bob 停顿了片刻,然后低声说:“不,我不能爱你!”

你能找到那个吗? :D

't over yet, though. "Hey!" yelled Bob. "What do you want?" I retorted. "I hate your guts!" "Why would I care?" "Because I love you!" "You do?" Bob paused for a moment before whispering "No, I couldn'

我会建议(如果您准备使用环视),您可以考虑做一些额外的检查(例如在第一个引号之前对空格或类似内容进行积极的回看)以确保您不匹配像 @987654324 这样的东西@ - 虽然如果没有先进行大量测试,我不会在任何解决方案上投入太多资金。在任一表达式的开头添加(?<=\s|^) 将避免上述情况...即:

(?<=\s|^)(["'])(?:\\.|(?!\1).)*\1                    #based on Tim's

(?<=\s|^)("(\\"|[^"])*"|'(\\'|[^'])*')               #based on my alternative

我不确定环视与非环视相比效率如何,因此上述两者可能是等效的,或者一个可能比另一个更有效 (?)

【讨论】:

Code Jockey 的一些优点,确实以这种方式解析英文文本是不明智的。但是,我实际上是在尝试在 mysql 代码中解析俄语文本(我在上面的代码中将 а-яА-ЯёЁ 更改为 a-zA-Z,以便这里的人们能够理解其含义),以及在解析字符串时在代码中,它们当然总是保证用一种或另一种引号括起来。

以上是关于正则表达式;反向引用字符集中不匹配的字符的主要内容,如果未能解决你的问题,请参考以下文章

具有奇怪行为的正则表达式:将字符串与反向引用匹配以允许转义以及单引号和双引号

正则表达式反向引用乘法[重复]

正则表达式

正则表达式

正则表达式

java正则表达式