正则表达式;反向引用字符集中不匹配的字符
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,以便这里的人们能够理解其含义),以及在解析字符串时在代码中,它们当然总是保证用一种或另一种引号括起来。以上是关于正则表达式;反向引用字符集中不匹配的字符的主要内容,如果未能解决你的问题,请参考以下文章