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

How do I match any character across multiple lines in a regular expression?

提问人:andyuk 提问时间:10/2/2008 最后编辑:Bobulousandyuk 更新时间:7/5/2023 访问量:991209

问:

例如,此正则表达式

(.*)<FooBar>

将匹配:

abcde<FooBar>

但是,如何让它在多行之间匹配呢?

abcde
fghij<FooBar>
正则表达式 多行 lua 模式 matlab octave boost oracle bash tcl postgresql r sed perl gnu-grep pcregrep php c# powershell python java kotlin groovy scala javascript c++ vba vbscript ruby tre base-r icu stringr stringi go swift objective-c re2 google-apps-script

评论

1赞 andyuk 10/2/2008
澄清;我最初使用Eclipse在多个文件中进行查找和替换。我从下面的答案中发现,我的问题是工具而不是正则表达式模式。

答:

1赞 nsayer 10/2/2008 #1

在语言中使用的上下文中,正则表达式作用于字符串,而不是行。因此,假设输入字符串有多行,您应该能够正常使用正则表达式。

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

基于行的正则表达式通常用于命令行,例如 egrep。

306赞 Paige Ruten 10/2/2008 #2

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

/(.*)<FooBar>/s

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

评论

1赞 Grace 4/11/2011
如果我想要一个新行而不是所有字符怎么办?
7赞 Paige Ruten 4/12/2011
@Grace:使用 \n 匹配换行符
6赞 Allen 5/9/2013
s 标志(现在?)无效,至少在 Chrome/V8 中是这样。请改用 /([\s\S]*)<FooBar>/ 字符类(匹配空格和非空格)而不是句点匹配器。有关详细信息,请参阅其他答案。
17赞 Derek 朕會功夫 7/13/2015
@Allen - JavaScript 不支持修饰符。相反,为了同样的效果而做。s[^]*
3赞 Ryan Buckley 7/16/2015
在 Ruby 中,使用 修饰符m
675赞 levik 10/2/2008 #3

试试这个:

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

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

评论

8赞 Ben Doom 10/2/2008
这取决于您使用的语言和/或工具。请让我们知道您正在使用什么,例如 Perl、PHP、CF、C#、sed、awk 等。
67赞 Potherca 3/10/2012
根据您的行尾,您可能需要((.|\n|\r)*)<FooBar>
4赞 acme 6/13/2012
没错 - 问题是关于 eclipse 的,标签也是如此。但公认的解决方案是PHP解决方案。你的应该是公认的解决方案......
55赞 Wiktor Stribiżew 7/18/2016
这是匹配多行输入的最差正则表达式。除非您使用的是 ElasticSearch,否则请不要使用它。使用 或 .[\s\S]*(?s).*
4赞 Snow 4/25/2019
在某些情况下,这种不必要的交替可能会导致灾难性的回溯。这不是一个好的一般模式。
9赞 Markus Jarderot 10/2/2008 #4

"."通常与换行符不匹配。大多数正则表达式引擎允许您添加 -flag(也称为 和 )以使换行符也匹配。 如果失败了,你可以做类似的事情。SDOTALLSINGLELINE"."[\S\s]

3赞 tloach 10/2/2008 #5

通常,不匹配换行符,因此请尝试..((.|\n)*)<foobar>

评论

5赞 Alan Moore 4/26/2009
不,不要那样做。如果需要匹配任何内容,包括行分隔符,请使用 DOTALL(又名 /s 或 SingleLine)修饰符。不仅 (.|\n) hack 使正则表达式效率降低,这甚至不正确。至少,它应该匹配 \r(回车)和 \n(换行符)。还有其他行分隔符,尽管很少使用。但是,如果您使用 DOTALL 标志,则不必担心它们。
2赞 opyate 11/30/2009
\R 是 Eclipse 中与平台无关的换行符匹配项。
1赞 jeckhart 10/16/2012
@opyate 您应该将其作为答案发布,因为这个小宝石非常有用。
0赞 ssc-hrep3 11/29/2016
你可以试试这个。它不会与内括号匹配,并且还考虑可选。\r((?:.|\r?\n)*)<foobar>
5赞 Bill 10/2/2008 #6

用:

/(.*)<FooBar>/s

使点 (.) 与回车符匹配。s

评论

0赞 Allen 5/9/2013
似乎这是无效的(Chrome):text.match(/a/s) SyntaxError:提供给 RegExp 构造函数“s”的标志无效
0赞 Morgan Touverey Quilling 4/21/2016
因为它在 JavaScript 正则表达式引擎中不受支持。这些标志存在于 PCRE 中,这是最完整的引擎(在 Perl 和 PHP 中可用)。PCRE 有 10 个标志(以及许多其他功能),而 JavaScript 只有 3 个标志 ()。sgmi
6赞 tye 10/2/2008 #7

请注意,这可能比(例如)(如果你的语言的正则表达式支持这种转义)和找到如何指定使 .也匹配换行符。或者您可以使用 POSIXy 替代品,例如 .(.|\n)*[\s\S]*[[:space:][:^space:]]*

1赞 Slee 3/26/2009 #8

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

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

我正在操作 HTML,因此在这种情况下,换行符对我来说并不重要。

我尝试了上面的所有建议,但没有运气。我正在使用 .NET 3.5 仅供参考。

评论

0赞 Vamshi Krishna 5/18/2018
我也在使用 .NET,似乎为我做了诀窍!(\s|\S)
0赞 Wiktor Stribiżew 9/15/2018
@VamshiKrishna 在 .NET 中,用于匹配任何字符。请勿使用会降低性能。(?s).(\s|\S)
0赞 Peter Mortensen 11/19/2021
.NET 正则表达式存在多行模式
5赞 shmall 4/13/2010 #9

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

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

评论

0赞 Peter Mortensen 11/19/2021
这是特定于特定平台的。它是什么编程语言和平台?C# / .NET?
0赞 Spangen 1/18/2011 #10

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

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

   }
...
...
}

如果我使用 regExp

if \(isTrue(.|\n)*}

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

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

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

43赞 Abbas Shahzadeh 7/30/2011 #11

在许多正则表达式方言中,会做你想做的事。/[\S\s]*<Foobar>/

评论

4赞 Allen 5/9/2013
从该链接:“JavaScript 和 VBScript 没有使点匹配换行符的选项。在这些语言中,您可以使用字符类(如 [\s\S])来匹配任何字符。而不是 .请改用 [\s\S](匹配空格和非空格)。
74赞 Paulo Merson 11/25/2011 #12

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

(?s).*<FooBar>

评论

1赞 Wiktor Stribiżew 7/18/2016
不是任何地方,只有在支持内联修饰符的正则表达式风格中,当然在 Ruby 中也不行。(?s) => (?m)
0赞 Pasupathi Rajamanickam 12/19/2018
有什么可以抨击的吗?
0赞 Peter Mortensen 11/19/2021
Eclipse 的底层正则表达式引擎是什么?Java/JDK 中的东西?
2赞 Sian Lerk Lau 4/4/2012 #13

溶液:

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

例:

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

来源:

评论

0赞 Peter Mortensen 11/19/2021
第一个链接以某种方式重定向到(我在主机文件中阻止了它)。该链接是否断开?www.facebook.com
0赞 Sian Lerk Lau 11/30/2021
我猜所有者决定将其重定向到 facebook 页面。我会删除它。
0赞 user1348737 4/22/2012 #14

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

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

假设我们想将 81 修改为其他值,比如 40。首先识别 ,然后跳过所有字符,包括 till 。正则表达式模式和替换规范为:.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(<PercentComplete>)replaceSpec

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

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

评论

0赞 Peter Mortensen 11/19/2021
什么编程语言?爪哇岛?
49赞 samwize 7/20/2012 #15
([\s\S]*)<FooBar>

该点匹配除换行符 () 之外的所有值。因此,请使用 ,它将匹配所有字符。\r\n\s\S

评论

0赞 J. Costa 8/25/2012
如果您使用的是 Objective-C .谢谢![text rangeOfString:regEx options:NSRegularExpressionSearch]
3赞 barclay 9/17/2015
这适用于 intelliJ 的查找和替换正则表达式,谢谢。
1赞 Ozkan 9/26/2017
这行得通。但它必须是第一次出现<FooBar>
18赞 user621354 8/3/2012 #16

Ruby 中,你可以使用 '' 选项(多行):m

/YOUR_REGEXP/m

有关详细信息,请参阅有关 ruby-doc.org正则表达式文档

评论

0赞 Peter Mortensen 11/19/2021
你确定它不应该代替吗?sm
8赞 Gordon 1/3/2013 #17

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

jadajada酒吧”

正则表达式:

Foo[\S\s]{1,10}.*Bar*
4赞 Kamahire 6/3/2013 #18

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

评论

1赞 Paul Draper 10/19/2013
这些不应该是反斜杠吗?
0赞 RandomInsano 12/22/2013
它们位于正则表达式的末尾,而不是在正则表达式的末尾。示例:/blah/s
0赞 3limin4t0r 9/26/2018
我猜你是说 JavaScript,而不是 Java?因为你可以只在 Java 和 JavaScript 中将标志添加到模式中,所以没有标志。ss
213赞 Wiktor Stribiżew 8/31/2017 #19

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

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

关于的另一个说明:默认情况下匹配任何字符(demo):(包含一个项目)。.str = "abcde\n fghij<Foobar>"; expression = '(.*)<Foobar>*'; [tokens,matches] = regexp(str,expression,'tokens','match');tokensabcde\n fghij

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

至于 (它是基于 POSIX 的),请使用 n 选项演示):select regexp_substr('abcde' || chr(10) ||' fghij<Foobar>', '(.*)<Foobar>', 1, 1, 'n', 1) as results from dual

基于 POSIX 的引擎

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

(demo)、 (demo)、 (TRE,没有 R 的基本 R 默认引擎,对于带有 stringr/stringi 模式或用于 stringr/stringi 模式的基本 R,请使用内联修饰符) (demo) 也以同样的方式处理。perl=TRUEperl=TRUE(?s).

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

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

查看演示

非基于 POSIX 的引擎

  • - 使用修饰符 PCRE_DOTALL 修饰符:(demospreg_match('~(.*)<Foobar>~s', $s, $m))
  • - 使用标志(演示):RegexOptions.Singleline
    - var result = Regex.Match(s, @"(.*)<Foobar>", RegexOptions.Singleline).Groups[1].Value;
    - var result = Regex.Match(s, @"(?s)(.*)<Foobar>").Groups[1].Value;
  • - 使用内联选项:(?s)$s = "abcde`nfghij<FooBar>"; $s -match "(?s)(.*)<Foobar>"; $matches[1]
  • - 使用修饰符(或开头的内联版本)(演示):s(?s)/(.*)<FooBar>/s
  • - 使用(或)标志或内联修饰符(demo):(然后,re.DOTALLre.S(?s)m = re.search(r"(.*)<FooBar>", s, flags=re.S)if m:print(m.group(1)))
  • - 使用修饰符(或内联标志)(演示):Pattern.DOTALL(?s)Pattern.compile("(.*)<FooBar>", Pattern.DOTALL)
  • - 用途 :RegexOption.DOT_MATCHES_ALL"(.*)<FooBar>".toRegex(RegexOption.DOT_MATCHES_ALL)
  • - 使用模式修饰符(演示):(?s)regex = /(?s)(.*)<FooBar>/
  • - 使用修饰符(演示):(?s)"(?s)(.*)<Foobar>".r.findAllIn("abcde\n fghij<Foobar>").matchData foreach { m => println(m.group(1)) }
  • - 使用 sdotAll) 标志或解决方法 / / / (demo):[^][\d\D][\w\W][\s\S]s.match(/([\s\S]*)<FooBar>/)[1]
  • () 使用或 JavaScript 解决方法(演示):std::regex[\s\S]regex rex(R"(([\s\S]*)<FooBar>)");
  • - 使用与 JavaScript 相同的方法。(注意RegExp 对象的属性有时被错误地认为是允许跨换行符匹配的选项,而实际上,它只是更改 和 行为以匹配的开头/结尾而不是字符串,与 JavaScript 正则表达式相同)([\s\S]*)<Foobar>MultiLine.^$
  • - 使用 /m MULTILINE 修饰符demo):s[/(.*)<Foobar>/m, 1]
  • r - Base R PCRE 正则表达式 - 使用:(demo (?s)regmatches(x, regexec("(?s)(.*)<FooBar>",x, perl=TRUE))[[1]][2])
  • ICU - 由 正则表达式引擎提供支持的 IN / 正则表达式功能。也使用 : (demostringrstringi(?s)stringr::str_match(x, "(?s)(.*)<FooBar>")[,2])
  • - 在开始时使用内联修饰符(演示):(?s)re: = regexp.MustCompile(`(?s)(.*)<FooBar>`)
  • - 使用 dotMatchesLineSeparators 或(更简单)将内联修饰符传递给模式:(?s)let rx = "(?s)(.*)<Foobar>"
  • - 与 Swift 相同。 最简单的工作方式,但以下是该选项的使用方式:(?s)NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionDotMatchesLineSeparators error:&regexError];
  • 使用修饰符 (demo): (在 Google 电子表格中,(?s)"(?s)(.*)<Foobar>"=REGEXEXTRACT(A2,"(?s)(.*)<Foobar>"))

关于(?s)的说明

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

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

POSIX说明

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

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

评论

14赞 Jan 10/16/2017
您应该从您的个人资料页面或其他内容(+1)链接到此出色的概述。
1赞 4/27/2018
您可能希望将其添加到 boost 项中:在 regex_constants 命名空间中,flag_type_的 : perl = ECMAScript = JavaScript = JScript = ::boost::regbase::normal = 0,默认为 Perl。程序员将为其正则表达式标志设置一个基本标志定义以反映这一点。仲裁器始终是内联修饰符。重置的位置。#define MOD regex_constants::perl | boost::regex::no_mod_s | boost::regex::no_mod_m(?-sm)(?s).*
1赞 Pasupathi Rajamanickam 12/19/2018
您也可以添加bash吗?
3赞 Wiktor Stribiżew 12/19/2018
@PasupathiRajamanickam Bash 使用 POSIX 正则表达式引擎,则匹配那里的任何字符(包括换行符)。请参阅此在线 Bash 演示.
1赞 Sebastián Espinosa 4/27/2020
你是一个传奇
23赞 Nambi_0915 8/6/2018 #20

我们还可以使用

(.*?\n)*?

在不贪婪的情况下匹配包括换行在内的所有内容。

这将使新行成为可选行

(.*?|\n)*?

评论

0赞 Wiktor Stribiżew 7/9/2020
除非您想以灾难性的回溯告终,否则永远不要使用。(.*?|\n)*?
2赞 Paul Chris Jones 2/27/2019 #21

在 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>

0赞 js2010 7/5/2019 #22

通常在 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
-1赞 Emma 10/7/2019 #23

选项 1

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

/(.*)<FooBar>/s

演示 1

选项 2

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

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

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

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

演示 2

正则表达式电路

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

enter image description here

1赞 hafiz031 8/29/2020 #24

尝试:假设您也允许空换行符。由于您允许任何字符,因此之前没有包含任何字符。.*\n*.*<FooBar><FooBar>

评论

1赞 Peter Mortensen 11/19/2021
看起来不对劲。为什么是两次“”?这可能适用于问题中的示例输入,但如果“<FooBar>”在第 42 行怎么办?.*
6赞 TheTechGuy 1/29/2022 #25

在记事本++中,您可以使用此

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

它将匹配整个表,从

行和列

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

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

评论

0赞 Just Me 4/4/2022
(\r\n)*- 超级答案。谢谢
6赞 Mateusz Kaflowski 8/26/2022 #26

这对我有用,是最简单的:

(\X*)<FooBar>

评论

0赞 Neil 6/8/2023
谢谢。。。这帮助我为我创建了多行正则表达式,即 Pattern regex = Pattern.compile(“(\\X*)From:*(\\X*)Sent:*(\\X*)To:*”);