如何在正则表达式中匹配多行中的任何字符?

Posted

技术标签:

【中文标题】如何在正则表达式中匹配多行中的任何字符?【英文标题】:How do I match any character across multiple lines in a regular expression? 【发布时间】:2008-10-01 18:48:22 【问题描述】:

例如,这个正则表达式

(.*)<FooBar>

将匹配:

abcde<FooBar>

但是如何让它匹配多行呢?

abcde
fghij<FooBar>

【问题讨论】:

澄清一下;我最初使用 Eclipse 在多个文件中进行查找和替换。我通过下面的答案发现我的问题是工具而不是正则表达式模式。 【参考方案1】:

试试这个:

((.|\n)*)<FooBar>

它基本上说“任何字符或换行符”重复零次或多次。

【讨论】:

这取决于您使用的语言和/或工具。请告诉我们您正在使用什么,例如 Perl、php、CF、C#、sed、awk 等。 根据您的行尾,您可能需要((.|\n|\r)*)&lt;FooBar&gt; 他说他正在使用 Eclipse。我认为这是正确的解决方案。我有同样的问题,这解决了它。 对 - 问题是关于 eclipse 的,标签也是如此。但公认的解决方案是 PHP 解决方案。你的应该是公认的解决方案... 这是匹配多行输入的最差的正则表达式。除非您使用 ElasticSearch,否则请不要使用它。使用[\s\S]*(?s).*【参考方案2】:

这取决于语言,但应该有一个可以添加到正则表达式模式的修饰符。在 PHP 中是:

/(.*)<FooBar>/s

末尾的 s 使点匹配 所有 个字符,包括换行符。

【讨论】:

如果我想要只是一个新行而不是所有字符怎么办? @Grace:使用 \n 匹配换行符 s 标志(现在?)无效,至少在 Chrome/V8 中是这样。而是使用 /([\s\S]*)/ 字符类(匹配空格和非空格] 而不是句点匹配器。有关更多信息,请参阅其他答案。 @Allen - javascript 不支持 s 修饰符。相反,请执行 [^]* 以获得相同的效果。 在 Ruby 中,使用 m 修饰符【参考方案3】:

问题是,. 模式可以匹配 any 字符吗?答案因发动机而异。主要区别在于该模式是由 POSIX 还是非 POSIX 正则表达式库使用。

关于 lua-patterns 的特别说明:它们不被视为正则表达式,但 . 匹配那里的任何字符,与基于 POSIX 的引擎相同。

关于matlab 和octave 的另一个说明:. 默认匹配任何字符(demo):str = "abcde\n fghij&lt;Foobar&gt;"; expression = '(.*)&lt;Foobar&gt;*'; [tokens,matches] = regexp(str,expression,'tokens','match');tokens 包含abcde\n fghij 项)。

此外,在所有boost 的正则表达式语法中,点默认匹配换行符。 Boost 的 ECMAScript 语法允许您使用 regex_constants::no_mod_m (source) 将其关闭。

至于oracle(基于POSIX),使用the n option(demo):select regexp_substr('abcde' || chr(10) ||' fghij&lt;Foobar&gt;', '(.*)&lt;Foobar&gt;', 1, 1, 'n', 1) as results from dual

基于 POSIX 的引擎

. 已经匹配换行符,因此不需要使用任何修饰符,请参阅bash (demo)。

tcl (demo)、postgresql (demo)、r(TRE,基本 R 默认引擎,不带 perl=TRUE,用于带 perl=TRUE 的基本 R 或 stringr/stringi 模式,使用(?s) 内联修饰符)(demo)也同样对待.

然而,大多数基于 POSIX 的工具会逐行处理输入。因此,. 与换行符不匹配,只是因为它们不在范围内。以下是一些如何覆盖它的示例:

sed - 有多种解决方法。最精确但不是很安全的是sed 'H;1h;$!d;x; s/\(.*\)&gt;&lt;Foobar&gt;/\1/'H;1h;$!d;x; 将文件吞入内存)。如果必须包含整行,可以考虑sed '/start_pattern/,/end_pattern/d' file(从开头删除将包含匹配行结束)或sed '/start_pattern/,/end_pattern///!d;;' file(排除匹配行)。 perl - perl -0pe 's/(.*)&lt;FooBar&gt;/$1/gs' &lt;&lt;&lt; "$str"-0 将整个文件吞入内存,-p 在应用-e 给出的脚本后打印文件)。请注意,使用 -000pe 将删除文件并激活“段落模式”,其中 Perl 使用连续换行符 (\n\n) 作为记录分隔符。 gnu-grep - grep -Poz '(?si)abc\K.*?(?=&lt;Foobar&gt;)' file。这里,z 启用文件 slurping,(?s) 启用 . 模式的 DOTALL 模式,(?i) 启用不区分大小写模式,\K 省略到目前为止匹配的文本,*? 是一个惰性量词,@ 987654420@ 匹配&lt;Foobar&gt; 之前的位置。 pcregrep - pcregrep -Mi "(?si)abc\K.*?(?=&lt;Foobar&gt;)" fileM 在此处启用文件 slurping)。注意pcregrep 是 macOS grep 用户的一个很好的解决方案。

See demos.

非 POSIX 引擎

php - 使用 s 修饰符 PCRE_DOTALL modifier: preg_match('~(.*)&lt;Foobar&gt;~s', $s, $m) (demo)

c# - 使用 RegexOptions.Singleline 标志 (demo): - var result = Regex.Match(s, @"(.*)&lt;Foobar&gt;", RegexOptions.Singleline).Groups[1].Value;- var result = Regex.Match(s, @"(?s)(.*)&lt;Foobar&gt;").Groups[1].Value;

powershell - 使用 (?s) 内联选项:$s = "abcde`nfghij&lt;FooBar&gt;"; $s -match "(?s)(.*)&lt;Foobar&gt;"; $matches[1]

perl - 使用s 修饰符(或(?s) 开头的内联版本)(demo):/(.*)&lt;FooBar&gt;/s

python - 使用re.DOTALL(或re.S)标志或(?s)内联修饰符(demo):m = re.search(r"(.*)&lt;FooBar&gt;", s, flags=re.S)(然后是if m:print(m.group(1))

java - 使用 Pattern.DOTALL 修饰符(或内联 (?s) 标志)(demo):Pattern.compile("(.*)&lt;FooBar&gt;", Pattern.DOTALL)

groovy - 使用 (?s) 模式内修饰符 (demo):regex = /(?s)(.*)&lt;FooBar&gt;/

scala - 使用(?s) 修饰符(demo):"(?s)(.*)&lt;Foobar&gt;".r.findAllIn("abcde\n fghij&lt;Foobar&gt;").matchData foreach m =&gt; println(m.group(1))

javascript - 使用[^] 或解决方法[\d\D] / [\w\W] / [\s\S] (demo):s.match(/([\s\S]*)&lt;FooBar&gt;/)[1]

c++ (std::regex) 使用 [\s\S] 或 JavaScript 解决方法 (demo):regex rex(R"(([\s\S]*)&lt;FooBar&gt;)");

vba vbscript - 使用与 JavaScript 中相同的方法 ([\s\S]*)&lt;Foobar&gt;。 (注意RegExp 对象的 MultiLine 属性有时被错误地认为是允许 . 跨换行符匹配的选项,而实际上,它只会更改 @987654461 @ 和 $ 行为匹配 lines 而不是 strings 的开始/结束,与 JavaScript 正则表达式相同) 行为。)

ruby - 使用/m MULTILINE modifier (demo):s[/(.*)&lt;Foobar&gt;/m, 1]

rtrebase-r - 基础 R PCRE 正则表达式 - 使用 (?s): regmatches(x, regexec("(?s)(.*)&lt;FooBar&gt;",x, perl=TRUE))[[1]][2] (demo)

ricustringrstringi - 在由 ICU 正则表达式引擎驱动的 stringr/stringi 正则表达式函数中。也可以使用(?s):stringr::str_match(x, "(?s)(.*)&lt;FooBar&gt;")[,2](demo)

go - 在开头使用内联修饰符(?s) (demo):re: = regexp.MustCompile(`(?s)(.*)&lt;FooBar&gt;`)

swift - 使用dotMatchesLineSeparators 或(更简单)将(?s) 内联修饰符传递给模式:let rx = "(?s)(.*)&lt;Foobar&gt;"

objective-c - 与 Swift 相同。 (?s) 工作最简单,但option can be used 是这样的:NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionDotMatchesLineSeparators error:&amp;regexError];

re2、google-apps-script - 使用 (?s) 修饰符 (demo):"(?s)(.*)&lt;Foobar&gt;"(在 Google 电子表格中,=REGEXEXTRACT(A2,"(?s)(.*)&lt;Foobar&gt;")

注意(?s)

在大多数非 POSIX 引擎中,(?s) 内联修饰符(或嵌入式标志选项)可用于强制 . 匹配换行符。

如果放置在模式的开头,(?s) 会更改模式中所有. 的行为。如果(?s) 放在开头之后的某个位置,则只有位于其右侧的.s 会受到影响除非这是传递给Python 的re 的模式。在 Python re 中,无论 (?s) 的位置如何,整个模式 . 都会受到影响。使用(?-s) 停止(?s) 效果。修改后的组可用于仅影响正则表达式模式的指定范围(例如,Delim1(?s:.*?)\nDelim2.* 将使第一个 .*? 匹配换行符,第二个 .* 将仅匹配该行的其余部分)。

POSIX 注释

在非 POSIX 正则表达式引擎中,要匹配任何字符,可以使用 [\s\S] / [\d\D] / [\w\W] 构造。

在 POSIX 中,[\s\S] 不匹配任何字符(如在 JavaScript 或任何非 POSIX 引擎中),因为括号表达式中不支持正则表达式转义序列。 [\s\S] 被解析为匹配单个字符的括号表达式,\sS

【讨论】:

你应该从你的个人资料页面链接到这个优秀的概述或其他东西 (+1)。 您可能希望将其添加到 boost 项中: 在 regex_constants 命名空间中,flag_type_'s : perl = ECMAScript = JavaScript = JScript = ::boost::regbase::normal = 0 默认为 Perl。程序员将为他们的正则表达式标志设置一个基本标志定义#define MOD regex_constants::perl | boost::regex::no_mod_s | boost::regex::no_mod_m 以反映这一点。并且仲裁器是 always 内联修饰符。 (?-sm)(?s).* 重置的位置。 你也可以为 bash 添加吗? @PasupathiRajamanickam Bash 使用 POSIX 正则表达式引擎,. 匹配那里的任何字符(包括换行符)。见this online Bash demo。 你是传奇【参考方案4】:

如果您使用的是 Eclipse 搜索,您可以启用“DOTALL”选项来制作 '.'匹配任何字符,包括行分隔符:只需在搜索字符串的开头添加“(?s)”。示例:

(?s).*<FooBar>

【讨论】:

不是在任何地方,只有在支持内联修饰符的正则表达式中,当然不是在(?s) => (?m)的Ruby中。 bash 有什么用吗? Eclipse 底层的正则表达式引擎是什么? Java/JDK 中有什么?【参考方案5】:

在许多正则表达式方言中,/[\S\s]*&lt;Foobar&gt;/ 可以满足您的需求。 Source

【讨论】:

来自该链接:“JavaScript 和 VBScript 没有使点匹配换行符的选项。在这些语言中,您可以使用诸如 [\s\S] 之类的字符类来匹配任何角色。”而不是 .请改用 [\s\S](匹配空格和非空格)。【参考方案6】:

([\s\S]*)&lt;FooBar&gt;

点匹配除换行符 (\r\n) 之外的所有内容。所以使用 \s\S,它将匹配所有字符。

【讨论】:

如果您使用的是 Objective-C [text rangeOfString:regEx options:NSRegularExpressionSearch],这将解决问题。谢谢! 这适用于 intelliJ 的 find&replace 正则表达式,谢谢。 这行得通。但它必须是第一次出现&lt;FooBar&gt;【参考方案7】:

在Ruby 中,您可以使用“m”选项(多行):

/YOUR_REGEXP/m

请参阅 ruby-doc.org 上的 the Regexp documentation 了解更多信息。

【讨论】:

你确定不应该是s 而不是m【参考方案8】:

我们也可以使用

(.*?\n)*?

匹配所有内容,包括换行符而不贪心。

这将使新行变为可选

(.*?|\n)*?

【讨论】:

永远不要使用(.*?|\n)*?,除非你想以灾难性的回溯结束。【参考方案9】:

"." 通常不匹配换行符。大多数正则表达式引擎允许您添加S-标志(也称为DOTALLSINGLELINE)以使"." 也匹配换行符。 如果失败,您可以执行[\S\s] 之类的操作。

【讨论】:

【参考方案10】:

对于 Eclipse,以下表达式有效:

jadajada 酒吧"

正则表达式:

Foo[\S\s]1,10.*Bar*

【讨论】:

【参考方案11】:

请注意,(.|\n)* 的效率可能低于(例如)[\s\S]*(如果您的语言的正则表达式支持此类转义),并且比查找如何指定使 .也匹配换行符。或者您可以使用 POSIXy 替代方案,例如 [[:space:][:^space:]]*

【讨论】:

【参考方案12】:

用途:

/(.*)<FooBar>/s

s 导致点 (.) 匹配回车符。

【讨论】:

似乎这是无效的 (Chrome): text.match(/a/s) SyntaxError: Invalid flags provided to RegExp constructor's' 因为它在 JavaScript RegEx 引擎中不受支持。 s 标志存在于 PCRE 中,这是最完整的引擎(在 Perl 和 PHP 中可用)。 PCRE 有 10 个标志(以及许多其他功能),而 JavaScript 只有 3 个标志 (gmi)。【参考方案13】:

使用 RegexOptions.Singleline。它将. 的含义更改为包含换行符。

Regex.Replace(content, searchText, replaceText, RegexOptions.Singleline);

【讨论】:

这是特定于特定平台的。它是什么编程语言和平台? C# / .NET?【参考方案14】:

在基于 Java 的正则表达式中,您可以使用 [\s\S]

【讨论】:

不应该是反斜杠吗? 它们位于正则表达式的末尾,而不是 in。示例:/blah/s 我猜你的意思是 JavaScript,而不是 Java?因为您可以在 Java 中将 s 标志添加到模式中,而 JavaScript 没有 s 标志。【参考方案15】:

一般来说,. 不匹配换行符,所以试试((.|\n)*)&lt;foobar&gt;

【讨论】:

不,不要那样做。如果您需要匹配包括行分隔符在内的任何内容,请使用 DOTALL(又名 /s 或 SingleLine)修饰符。 (.|\n) hack 不仅降低了正则表达式的效率,甚至不正确。至少,它应该匹配 \r(回车)和 \n(换行)。还有其他行分隔符,尽管很少使用。但如果你使用 DOTALL 标志,你就不必担心它们。 \R 是 Eclipse 中换行符的平台无关匹配项。 @opyate 您应该将此作为答案发布,因为这个小宝石非常有用。 你可以试试这个。它不会匹配内括号,还可以考虑可选的\r.:((?:.|\r?\n)*)&lt;foobar&gt;【参考方案16】:

解决办法:

使用模式修饰符sU 将在 PHP 中获得所需的匹配。

示例:

preg_match('/(.*)/sU', $content, $match);

来源:

Pattern Modifiers

【讨论】:

第一个链接以某种方式重定向到www.facebook.com(我已在hosts file 中阻止)。该链接是否损坏? 我猜所有者决定将其重定向到 Facebook 页面。我会删除它。【参考方案17】:

在语言中使用的上下文中,正则表达式作用于字符串,而不是行。所以你应该可以正常使用正则表达式,假设输入字符串有多行。

在这种情况下,给定的正则表达式将匹配整个字符串,因为存在“”。根据正则表达式实现的具体情况,$1 值(从“(.*)”获得)将是“fghij”或“abcde\nfghij”。正如其他人所说,某些实现允许您控制是否“。”将匹配换行符,让您选择。

基于行的正则表达式通常用于 egrep 之类的命令行。

【讨论】:

【参考方案18】:

尝试:.*\n*.*&lt;FooBar&gt; 假设您也允许空白换行符。因为您允许任何字符,包括 &lt;FooBar&gt; 之前的任何字符。

【讨论】:

看起来不太对劲。为什么两次“.*”?这可能适用于问题中的示例输入,但如果“”在第 42 行怎么办?【参考方案19】:

我遇到了同样的问题,并以可能不是最好的方式解决了它,但它确实有效。我在进行真正的比赛之前替换了所有换行符:

mystring = Regex.Replace(mystring, "\r\n", "")

我正在处理 html,所以在这种情况下,换行对我来说并不重要。

我尝试了上述所有建议,但没有成功。我正在使用 .NET 3.5 仅供参考。

【讨论】:

我也在使用 .NET,(\s|\S) 似乎对我有用! @VamshiKrishna 在 .NET 中,使用 (?s) 使 . 匹配任何字符。不要使用(\s|\S),这会降低性能。 有一个multi-line mode for .NET regular expressions。【参考方案20】:

在 JavaScript 中,您可以使用 [^]* 搜索零到无限字符,包括换行符。

$("#find_and_replace").click(function() 
  var text = $("#textarea").val();
  search_term = new RegExp("[^]*<Foobar>", "gi");;
  replace_term = "Replacement term";
  var new_text = text.replace(search_term, replace_term);
  $("#textarea").val(new_text);
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="find_and_replace">Find and replace</button>
<br>
<textarea ID="textarea">abcde
fghij&lt;Foobar&gt;</textarea>

【讨论】:

【参考方案21】:

在notepad++中你可以使用这个

<table (.|\r\n)*</table>

它将匹配整个表格,从

行和列

你可以让它变得贪婪,使用以下方法,这样它就会匹配第一个、第二个等表,而不是一次全部匹配

<table (.|\r\n)*?</table>

【讨论】:

【参考方案22】:

我想在 Java 中匹配特定的 if 块:

   ...
   ...
   if(isTrue)
       doAction();

   
...
...

如果我使用正则表达式

if \(isTrue(.|\n)*

它包含了方法块的右大括号,所以我使用了

if \(!isTrue([^.]|\n)*

从通配符匹配中排除右大括号。

【讨论】:

【参考方案23】:

通常我们必须用几个关键字来修改子字符串,这些关键字分布在子字符串前面的行中。考虑一个 XML 元素:

<TASK>
  <UID>21</UID>
  <Name>Architectural design</Name>
  <PercentComplete>81</PercentComplete>
</TASK>

假设我们想将 81 修改为其他值,比如 40。首先识别.UID.21..UID.,然后跳过包括\n 在内的所有字符,直到.PercentCompleted.。正则表达式模式和替换规范是:

String hw = new String("<TASK>\n  <UID>21</UID>\n  <Name>Architectural design</Name>\n  <PercentComplete>81</PercentComplete>\n</TASK>");
String pattern = new String ("(<UID>21</UID>)((.|\n)*?)(<PercentComplete>)(\\d+)(</PercentComplete>)");
String replaceSpec = new String ("$1$2$440$6");
// Note that the group (<PercentComplete>) is $4 and the group ((.|\n)*?) is $2.

String iw = hw.replaceFirst(pattern, replaceSpec);
System.out.println(iw);

<TASK>
  <UID>21</UID>
  <Name>Architectural design</Name>
  <PercentComplete>40</PercentComplete>
</TASK>

子组(.|\n) 可能是缺少的组$3。如果我们让它不被(?:.|\n) 捕获,那么$3 就是(&lt;PercentComplete&gt;)。所以pattern和replaceSpec也可以是:

pattern = new String("(<UID>21</UID>)((?:.|\n)*?)(<PercentComplete>)(\\d+)(</PercentComplete>)");
replaceSpec = new String("$1$2$340$5")

并且替换像以前一样正常工作。

【讨论】:

什么编程语言?爪哇?【参考方案24】:

通常在 PowerShell 中搜索三个连续的行,它看起来像:

$file = Get-Content file.txt -raw

$pattern = 'lineone\r\nlinetwo\r\nlinethree\r\n'     # "Windows" text
$pattern = 'lineone\nlinetwo\nlinethree\n'           # "Unix" text
$pattern = 'lineone\r?\nlinetwo\r?\nlinethree\r?\n'  # Both

$file -match $pattern

# output
True

奇怪的是,这将是提示符下的 Unix 文本,但文件中的 Windows 文本:

$pattern = 'lineone
linetwo
linethree
'

这是一种打印行尾的方法:

'lineone
linetwo
linethree
' -replace "`r",'\r' -replace "`n",'\n'

# Output
lineone\nlinetwo\nlinethree\n

【讨论】:

【参考方案25】:

选项 1

一种方法是使用s 标志(就像接受的答案一样):

/(.*)<FooBar>/s

Demo 1

选项 2

第二种方法是使用m(多行)标志和以下任何模式:

/([\s\S]*)<FooBar>/m

/([\d\D]*)<FooBar>/m

/([\w\W]*)<FooBar>/m

Demo 2

正则表达式电路

jex.im 可视化正则表达式:

【讨论】:

以上是关于如何在正则表达式中匹配多行中的任何字符?的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式匹配多行字符串中的字符串

正则表达式

正则表达式位置匹配攻略【转】

正则表达式 - 查找所有空格并忽略多行字符串中的连字符分隔的单词

Python: 正则表达式匹配多行,实现多行匹配模式

如何检查字符串是不是与 node.js 中的任何正则表达式数组匹配?