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

例如,这个正则表达式

(.*)<FooBar>

将匹配:

abcde<FooBar>

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

abcde
fghij<FooBar>
879508 次浏览

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

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

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

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

/(.*)<FooBar>/s

结尾的<年代trong>年代使点匹配所有字符,包括换行符。

试试这个:

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

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

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

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

使用:

/(.*)<FooBar>/s

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

请注意,(.|\n)*可能比(例如)[\s\S]*(如果您的语言的正则表达式支持这种转义)更低效,也比查找如何指定制造的修饰符更有效。还要匹配换行符。或者你也可以选择POSIXy,比如[[:space:][:^space:]]*

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

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

我在操作HTML,所以在这种情况下换行对我来说并不重要。

我尝试了上面所有的建议,但都没有成功。我使用的是。net 3.5供你参考。

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

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

我想在Java中匹配一个特定的如果块:

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


}
...
...
}

如果我使用regExp

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

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

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

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

在许多正则表达式方言中,/[\S\s]*<Foobar>/将做您想做的事情。# EYZ1

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

(?s).*<FooBar>

解决方案:

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

例子:

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

来源:

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

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

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

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")

而且替换后的机器和以前一样工作正常。

# EYZ0

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

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

/YOUR_REGEXP/m

更多信息请参见Regexp文档ruby-doc.org

对于Eclipse,下面的表达式是有效的:

喷火

jadajada Bar"

正则表达式:

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

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

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

关于需要特别注意:它们不被认为是正则表达式,但是.匹配其中的任何字符,与基于posix的引擎相同。

关于的另一个注意事项:.默认匹配任何字符(演示): str = "abcde\n fghij<Foobar>"; expression = '(.*)<Foobar>*'; [tokens,matches] = regexp(str,expression,'tokens','match'); (tokens包含abcde\n fghij项)。

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

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

# EYZ0:

仅仅.就已经匹配换行符了,所以不需要使用任何修饰符,参见 (演示)。

(演示), (演示), (TRE,基础R默认引擎没有perl=TRUE,对于基础R与perl=TRUEstringr/perl=TRUE0模式,使用(?s)内联修饰器)(perl=TRUE1)也以同样的方式对待.

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

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

# EYZ0。

# EYZ0:

  • 使用s修饰符PCRE_DOTALL修饰符: preg_match('~(.*)<Foobar>~s', $s, $m) (演示)

  • < p > # EYZ3 -使用# EYZ0标志(# EYZ4):
    - # EYZ1
    - # EYZ2

  • -使用(?s) inline选项:$s = "abcde`nfghij<FooBar>"; $s -match "(?s)(.*)<Foobar>"; $matches[1]

  • -使用s修饰符(或(?s)开头的内联版本)(演示): /(.*)<FooBar>/s

  • 使用re.DOTALL(或re.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)) }

  • -使用[^]或绕过[\d\D] / [\w\W] / [\s\S] (演示): s.match(/([\s\S]*)<FooBar>/)[1]

  • (std::regex)使用[\s\S]或JavaScript工作区(演示): regex rex(R"(([\s\S]*)<FooBar>)");

  • -使用与JavaScript中相同的方法,([\s\S]*)<Foobar>。(请注意: RegExp对象的MultiLine属性有时被错误地认为是允许.匹配跨换行符的选项,而实际上,它只改变^$行为来匹配MultiLine0的开始/结束,而不是MultiLine1,与JavaScript正则表达式相同) 行为。)< / p >

  • -使用/m MULTILINE修饰符 (演示): s[/(.*)<Foobar>/m, 1]

  • - Base R PCRE regexp -使用(?s): regmatches(x, regexec("(?s)(.*)<FooBar>",x, perl=TRUE))[[1]][2] (演示)

  • -在stringr/stringi正则表达式函数中,由ICU正则表达式引擎提供动力。也可以使用(?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];

  • -使用(?s)修饰符(演示): "(?s)(.*)<Foobar>"(在谷歌电子表格中,=REGEXEXTRACT(A2,"(?s)(.*)<Foobar>"))

# EYZ1:

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

如果放在模式的开头,(?s)将改变模式中所有.的行为。如果(?s)被放置在开始之后的某个地方,只有位于它右边的# eyz1会受到影响,这是传递给Python的re的模式。在Python re中,无论(?s)位置如何,整个模式.都会受到影响。使用(?-s)停止(?s)效果。修改后的组只能用于影响正则表达式模式的指定范围(例如,.0将使第一个.1匹配换行,第二个.2只匹配行其余部分)。

# EYZ0:

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

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

我们也可以用

(.*?\n)*?

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

这将使新行成为可选的

(.*?|\n)*?

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

$("#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>

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

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

/(.*)<FooBar>/s

Demo 1

选项2

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

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

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

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

Demo 2

RegEx电路

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

enter image description here

尝试:.*\n*.*<FooBar>,假设你也允许空换行。因为你允许任何字符在<FooBar>之前不包括任何字符。

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

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

它将匹配从。开始的整个表

行和列

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

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

这对我来说是最简单的方法:

(\X*)<FooBar>