如何在正则表达式中匹配“直到此字符序列的任何内容”?

How can I match "anything up until this sequence of characters" in a regular expression?

提问人:callum 提问时间:8/20/2011 最后编辑:Arvind Kumar Avinashcallum 更新时间:10/16/2023 访问量:1270801

问:

采用以下正则表达式:.这将匹配字符串开头的任何单个字符,但 abc 除外。/^[^abc]/

如果在它后面添加一个 – – 正则表达式将继续将每个后续字符添加到结果中,直到它遇到 、 或 */^[^abc]*/abc

例如,对于源字符串,表达式将匹配到 。"qwerty qwerty whatever abc hello""qwerty qwerty wh"

但是,如果我希望匹配的字符串是呢?"qwerty qwerty whatever "

换句话说,我怎样才能将所有内容匹配到(但不包括)确切的序列"abc"

正则表达式

评论

0赞 Toto 8/20/2011
你是什么意思?match but not including
9赞 callum 8/20/2011
我的意思是我想匹配——不包括“abc”。换句话说,我不希望生成的匹配是 ."qwerty qwerty whatever ""qwerty qwerty whatever abc"
4赞 Wylliam Judd 5/24/2018
在 javascript 中,您可以 .当然不是这个问题的官方答案,但我发现它比正则表达式更直接。do string.split('abc')[0]

答:

215赞 Jared Ng 8/20/2011 #1

如果您希望捕获“abc”之前的所有内容:

/^(.*?)abc/

解释:

( )捕获括号内的表达式,以便使用 、 等进行访问。$1$2

^比赛线的起点

.*不贪婪地匹配任何内容(匹配所需的最小字符数)- [1]?

[1] 之所以需要这样做,是因为否则,在以下字符串中:

whatever whatever something abc something abc

默认情况下,正则表达式是贪婪的,这意味着它将尽可能地匹配。因此,将匹配“无论什么东西,abc什么”。添加非贪婪量词会使正则表达式仅匹配“无论什么东西”。/^.*abc/?

评论

10赞 callum 8/20/2011
谢谢,但你的那个确实在比赛中包含了 abc。换句话说,结果匹配是“无论什么 abc”。
2赞 Jared Ng 8/20/2011
你能解释一下你最终想做什么吗?如果你的方案是:(A)你想得到“abc”之前的所有内容--只需在你想要捕获的内容周围使用括号。(B) 你想将字符串与“abc”匹配——无论如何你都必须检查 abc,所以无论如何它都需要成为正则表达式的一部分。你还能如何检查它是否在那里?
1赞 CodeManX 8/23/2015
sed似乎不支持非贪婪匹配,也不支持环视()。我还能做些什么?示例命令:返回 ,但我希望......(?=...)echo "ONE: two,three, FOUR FIVE, six,seven" | sed -n -r "s/^ONE: (.+?), .*/\1/p"two,three, FOUR FIVEtwo,three
1赞 Jared Ng 8/30/2015
@CoDEmanX 您可能应该将其作为您自己的单独问题而不是评论发布,尤其是因为它专门针对 sed。话虽如此,为了解决您的问题:您可能想看看这个问题的答案。另请注意,在您的示例中,非贪婪感知解释器将返回 ,而不是 。twotwo,three
4赞 jave.web 9/1/2016
这就是每个正则表达式答案应该看起来的样子 - 所有部分的示例和解释......
-2赞 Jakob Jingleheimer 8/20/2011 #2

标记字符串的末尾,所以像这样的东西应该可以工作:你要寻找任何不以 的迭代结尾的东西,但它必须在末尾$[[^abc]*]$abc

此外,如果您使用带有正则表达式的脚本语言(如 PHP 或 JavaScript),它们有一个搜索函数,当它第一次遇到模式时会停止(您可以指定从左侧开始或从右侧开始,或者使用 php,您可以执行内爆来镜像字符串)。

-1赞 Software Mechanic 8/20/2011 #3

我相信你需要子表达式。您可以对子表达式使用普通括号。()

这部分来自 grep 手册:

反向引用和子表达式

反向引用 \n(其中 n 为单个数字)与子字符串匹配 先前由 正则表达式。

做类似的事情应该可以解决问题。^[^(abc)]

评论

1赞 callum 8/20/2011
对不起,这不起作用。将 abc 放在括号中似乎没有任何区别。它们仍然被视为“a OR b OR c”。
0赞 Paul Masri-Stone 5/7/2021
[^...]表示“不是方括号内的任何字符,而不是”不是下面的标记“,所以这不起作用。
1498赞 sidyll 8/20/2011 #4

您没有指定您正在使用的正则表达式,但这将 在任何可以被认为是“完整”的最受欢迎的作品中工作。

/.+?(?=abc)/

运作方式

该部分是 (一个或多个 任何事情)。当我们使用时,引擎基本上会匹配一切。 然后,如果正则表达式中有其他内容,它将按步骤返回 尝试匹配以下部分。这是贪婪的行为, 意思是尽可能地满足.+?.+.+

使用时,而不是一次匹配所有并返回 其他条件(如果有),引擎将通过以下方式匹配下一个字符 步骤,直到正则表达式的后续部分匹配(如果有),再次匹配。 这是不贪婪的,意思是尽可能少地匹配 满意.+?

/.+X/  ~ "abcXabcXabcX"        /.+/  ~ "abcXabcXabcX"
          ^^^^^^^^^^^^                  ^^^^^^^^^^^^

/.+?X/ ~ "abcXabcXabcX"        /.+?/ ~ "abcXabcXabcX"
          ^^^^                          ^

之后我们有 {contents}宽度为零 断言环顾四周。这种分组结构与其 内容,但不计为匹配的字符(宽度为零)。它 仅当它是否匹配(断言)时才返回。(?=)

因此,换句话说,正则表达式意味着:/.+?(?=abc)/

尽可能少地匹配任何字符,直到找到“abc”, 不算“ABC”。

评论

32赞 einord 10/13/2016
如果应该捕获换行符,这可能不适用于换行符。
4赞 robbie 4/5/2017
和 和有什么不一样?.+?.*
9赞 jinglesthula 4/18/2017
@robbie0630 表示 1 或更多,其中表示 0 或更多。包含/排除将使其贪婪或不贪婪。+*?
2赞 JohnWrensby 6/2/2017
@testerjoe2 /.+?(?=abc|xyz)/
12赞 Karan Shishoo 8/13/2018
我注意到,如果您寻找的模式不存在,这将无法选择任何内容,相反,如果您使用您可以链接以排除您不想要的模式,即使该模式不存在,它仍然会根据需要获取所有内容^(?:(?!abc)(?!def).)*
9赞 Gaijinhunter 8/20/2011 #5

您需要查看断言,例如 ..+? (?=abc)

请参见: Lookahead 和 Lookbehind 零长度断言

请注意,这与 不同。括号内不是字符串 - 每个字符只是其中一种可能性。在括号外,它成为字符串。[abc]abc

98赞 Devy 9/22/2015 #6

正如 Jared Ng 和 @Issun 所指出的,解决这种正则表达式的关键,例如“将所有内容匹配到某个单词或子字符串”或“匹配某个单词或子字符串之后的所有内容”,称为“环视”零长度断言。在此处阅读有关它们的更多信息

在您的特定情况下,可以通过积极展望未来来解决:.+?(?=abc)

一张图片胜过千言万语。请参阅屏幕截图中的详细说明。

Regex101 Screenshot

评论

61赞 Tom 5/7/2019
.+?(?=abc)可复制粘贴的正则表达式更有价值。
1赞 Royi 5/4/2020
排除前导空格呢?
1赞 Srivathsa Harish Venkataramana 11/18/2020
可分享的链接也比截图更有价值,开个玩笑,谢谢你的回答
0赞 Peter Mortensen 4/30/2022
谁是“Issun”?它指的是什么答案?
0赞 Devy 5/1/2022
Issun 的帐户已不复存在。但他们指的是“环顾四周”——请参阅我在答案中提供的链接。
-7赞 Balakrishna Gondesi 10/28/2016 #7

试试这个:

.+?efg

查询:

select REGEXP_REPLACE ('abcdefghijklmn','.+?efg', '') FROM dual;

输出:

hijklmn
8赞 Aesthetic 11/30/2016 #8

对于 Java 中的正则表达式,我相信在大多数正则表达式引擎中也是如此,如果您想包含最后一部分,这将起作用:

.+?(abc)

例如,在以下行中:

I have this very nice senabctence

选择所有字符,直到“abc”,并包括 abc。

使用我们的正则表达式,结果将是:I have this very nice senabc

测试一下:https://regex101.com/r/mX51ru/1

2赞 Ponmurugan Mohanraj 5/25/2017 #9

这对正则表达式来说是有道理的。

可以从以下正则表达式命令中获取确切的单词:

("(.*?)")/g

在这里,我们可以全局获得属于双引号内的确切单词。

例如,如果我们的搜索文本是

这是“双引号”单词的示例

然后我们将从该句子中得到“双引号”。

评论

1赞 Yunnosch 5/25/2017
欢迎来到 StackOverflow,感谢您的帮助。然而,我发现很难看出这对问题中陈述的目标有何帮助。你能详细说明一下吗?你能把它应用到给定的例子中吗?你似乎专注于处理,这对我来说似乎与这个问题无关。"
1赞 Ponmurugan Mohanraj 5/25/2017
嗨,我已经解释了如何在特殊字符之间获取单词或句子。在这里,我们的问题也是“直到特殊字符序列的任何内容”。所以我尝试用双引号在这里解释。谢谢。
5赞 Alvaro Rodriguez Scelza 11/21/2018 #10

所以我不得不即兴发挥......一段时间后,我设法达到了我需要的正则表达式:

Enter image description here

如您所见,我最多需要在“grp-bps”文件夹之前使用一个文件夹,不包括最后一个破折号。并且要求在“grp-bps”文件夹之后至少有一个文件夹。

复制粘贴的文本版本(将文本的“grp-bps”更改为“grp-bps”):

.*\/grp-bps\/[^\/]+

在寻求帮助来解决我的问题后,我以这个 Stack Overflow 问题结束,但我没有找到任何解决方案:(

评论

9赞 kiradotee 2/18/2019
没有文字版本?🙄
7赞 David Mulder 3/5/2020 #11

在 Python 中:

.+?(?=abc)适用于单行情况。

[^]+?(?=abc)不起作用,因为 Python 无法将 [^] 识别为有效的正则表达式。 要使多行匹配正常工作,您需要使用 re.DOTALL 选项,例如:

re.findall('.+?(?=abc)', data, re.DOTALL)
32赞 Paul Masri-Stone 5/7/2021 #12

溶液

/[\s\S]*?(?=abc)/

这将匹配

所有内容,直到(但不包括)确切的顺序"abc"

正如 OP 所要求的那样,即使源字符串包含换行符即使序列以 abc 开头。但是,如果源字符串可能包含换行符,请务必包含 multiline 标志。m

运作方式

\s表示任何格字符(例如空格、制表符、换行符)

\S指任何非空格字符;即与\s

Together 表示任何角色。这与不匹配换行符几乎相同。[\s\S]..

*表示前一个标记的出现次数为 0+。我用了它,而不是在源字符串以 .+abc

(?=被称为积极展望。它要求与括号中的字符串匹配,但在括号之前停止,因此表示“最多但不包括,但必须存在于源字符串中”。(?=abc)abcabc

?介于 和 之间,表示懒惰(又名非贪婪)。即停在第一个.如果没有这个,它将捕获每个字符,直到最终出现多次。[\s\S]*(?=abc)abcabcabc

3赞 pratsbhatt 5/27/2021 #13

我想扩展 sidyll 对不区分大小写的正则表达式版本的答案。

如果要匹配 abc/Abc/ABC...不区分大小写,我需要这样做,使用以下正则表达式。

.+?(?=(?i)abc)

解释:

(?i) - This will make the following abc match case insensitively.

正则表达式的另一种解释与 sidyll 指出的相同。

8赞 proseosoc 5/22/2022 #14

如果没有 ABC,则从开始到“ABC”或“Line End”之前匹配

(1) 如果字符串在任何地方都不包含 ABC,则匹配整个字符串

(2) 不匹配空字符串

(不检查带换行符的字符串)

^.+?(?=ABC|$)
2赞 EzPizza 12/6/2022 #15

您的问题没有指定后续字符序列是否可选,但所有其他答案都假定始终给出该序列。所以这里有一个,如果序列是可选的。

例如,如果将代码匹配到行注释(如 或),则行注释本身可能是可选的,但可能仍希望匹配前面的代码。foo # ...foo // ...

在这种情况下,我会使用(或行注释:或)。^(?:(?!abc).)*^(?:(?!#).)*^(?:(?!\/\/).)*

说明:
标记行的开头。 是一个非捕获组,因为常规组会额外捕获组中的最后一个匹配字母,这是我们不需要的。
在组内,我们使用负前瞻和 ,因此除了特定序列外,所有内容都匹配。这重复 0 到无限次。如果只想匹配非空字符串,请改用。
^(?:)(?!).*+