如何在正则表达式中匹配多行中的任何字符?
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)*)<FooBar>
他说他正在使用 Eclipse。我认为这是正确的解决方案。我有同样的问题,这解决了它。
对 - 问题是关于 eclipse 的,标签也是如此。但公认的解决方案是 PHP 解决方案。你的应该是公认的解决方案...
这是匹配多行输入的最差的正则表达式。除非您使用 ElasticSearch,否则请不要使用它。使用[\s\S]*
或(?s).*
。【参考方案2】:
这取决于语言,但应该有一个可以添加到正则表达式模式的修饰符。在 PHP 中是:
/(.*)<FooBar>/s
末尾的 s 使点匹配 所有 个字符,包括换行符。
【讨论】:
如果我想要只是一个新行而不是所有字符怎么办? @Grace:使用 \n 匹配换行符 s 标志(现在?)无效,至少在 Chrome/V8 中是这样。而是使用 /([\s\S]*)s
修饰符。相反,请执行 [^]*
以获得相同的效果。
在 Ruby 中,使用 m
修饰符【参考方案3】:
问题是,.
模式可以匹配 any 字符吗?答案因发动机而异。主要区别在于该模式是由 POSIX 还是非 POSIX 正则表达式库使用。
关于 lua-patterns 的特别说明:它们不被视为正则表达式,但 .
匹配那里的任何字符,与基于 POSIX 的引擎相同。
关于matlab 和octave 的另一个说明:.
默认匹配任何字符(demo):str = "abcde\n fghij<Foobar>"; expression = '(.*)<Foobar>*'; [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<Foobar>', '(.*)<Foobar>', 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 '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 - perl -0pe 's/(.*)<FooBar>/$1/gs' <<< "$str"
(-0
将整个文件吞入内存,-p
在应用-e
给出的脚本后打印文件)。请注意,使用 -000pe
将删除文件并激活“段落模式”,其中 Perl 使用连续换行符 (\n\n
) 作为记录分隔符。
gnu-grep - grep -Poz '(?si)abc\K.*?(?=<Foobar>)' file
。这里,z
启用文件 slurping,(?s)
启用 .
模式的 DOTALL 模式,(?i)
启用不区分大小写模式,\K
省略到目前为止匹配的文本,*?
是一个惰性量词,@ 987654420@ 匹配<Foobar>
之前的位置。
pcregrep - pcregrep -Mi "(?si)abc\K.*?(?=<Foobar>)" file
(M
在此处启用文件 slurping)。注意pcregrep
是 macOS grep
用户的一个很好的解决方案。
See demos.
非 POSIX 引擎:
php - 使用 s
修饰符 PCRE_DOTALL modifier: preg_match('~(.*)<Foobar>~s', $s, $m)
(demo)
c# - 使用 RegexOptions.Singleline
标志 (demo): - var result = Regex.Match(s, @"(.*)<Foobar>", RegexOptions.Singleline).Groups[1].Value;
- var result = Regex.Match(s, @"(?s)(.*)<Foobar>").Groups[1].Value;
powershell - 使用 (?s)
内联选项:$s = "abcde`nfghij<FooBar>"; $s -match "(?s)(.*)<Foobar>"; $matches[1]
perl - 使用s
修饰符(或(?s)
开头的内联版本)(demo):/(.*)<FooBar>/s
python - 使用re.DOTALL
(或re.S
)标志或(?s)
内联修饰符(demo):m = re.search(r"(.*)<FooBar>", s, flags=re.S)
(然后是if m:
,print(m.group(1))
)
java - 使用 Pattern.DOTALL
修饰符(或内联 (?s)
标志)(demo):Pattern.compile("(.*)<FooBar>", Pattern.DOTALL)
groovy - 使用 (?s)
模式内修饰符 (demo):regex = /(?s)(.*)<FooBar>/
scala - 使用(?s)
修饰符(demo):"(?s)(.*)<Foobar>".r.findAllIn("abcde\n fghij<Foobar>").matchData foreach m => println(m.group(1))
javascript - 使用[^]
或解决方法[\d\D]
/ [\w\W]
/ [\s\S]
(demo):s.match(/([\s\S]*)<FooBar>/)[1]
c++ (std::regex
) 使用 [\s\S]
或 JavaScript 解决方法 (demo):regex rex(R"(([\s\S]*)<FooBar>)");
vba vbscript - 使用与 JavaScript 中相同的方法 ([\s\S]*)<Foobar>
。 (注意:RegExp
对象的 MultiLine
属性有时被错误地认为是允许 .
跨换行符匹配的选项,而实际上,它只会更改 @987654461 @ 和 $
行为匹配 lines 而不是 strings 的开始/结束,与 JavaScript 正则表达式相同)
行为。)
ruby - 使用/m
MULTILINE modifier (demo):s[/(.*)<Foobar>/m, 1]
rtrebase-r - 基础 R PCRE 正则表达式 - 使用 (?s)
: regmatches(x, regexec("(?s)(.*)<FooBar>",x, perl=TRUE))[[1]][2]
(demo)
ricustringrstringi - 在由 ICU 正则表达式引擎驱动的 stringr
/stringi
正则表达式函数中。也可以使用(?s)
:stringr::str_match(x, "(?s)(.*)<FooBar>")[,2]
(demo)
go - 在开头使用内联修饰符(?s)
(demo):re: = regexp.MustCompile(`(?s)(.*)<FooBar>`)
swift - 使用dotMatchesLineSeparators
或(更简单)将(?s)
内联修饰符传递给模式:let rx = "(?s)(.*)<Foobar>"
objective-c - 与 Swift 相同。 (?s)
工作最简单,但option can be used 是这样的:NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionDotMatchesLineSeparators error:&regexError];
re2、google-apps-script - 使用 (?s)
修饰符 (demo):"(?s)(.*)<Foobar>"
(在 Google 电子表格中,=REGEXEXTRACT(A2,"(?s)(.*)<Foobar>")
)
注意(?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]
被解析为匹配单个字符的括号表达式,\
或 s
或 S
。
【讨论】:
你应该从你的个人资料页面链接到这个优秀的概述或其他东西 (+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]*<Foobar>/
可以满足您的需求。 Source
【讨论】:
来自该链接:“JavaScript 和 VBScript 没有使点匹配换行符的选项。在这些语言中,您可以使用诸如 [\s\S] 之类的字符类来匹配任何角色。”而不是 .请改用 [\s\S](匹配空格和非空格)。【参考方案6】:([\s\S]*)<FooBar>
点匹配除换行符 (\r\n) 之外的所有内容。所以使用 \s\S,它将匹配所有字符。
【讨论】:
如果您使用的是 Objective-C[text rangeOfString:regEx options:NSRegularExpressionSearch]
,这将解决问题。谢谢!
这适用于 intelliJ 的 find&replace 正则表达式,谢谢。
这行得通。但它必须是第一次出现<FooBar>
【参考方案7】:
在Ruby 中,您可以使用“m
”选项(多行):
/YOUR_REGEXP/m
请参阅 ruby-doc.org 上的 the Regexp documentation 了解更多信息。
【讨论】:
你确定不应该是s
而不是m
?【参考方案8】:
我们也可以使用
(.*?\n)*?
匹配所有内容,包括换行符而不贪心。
这将使新行变为可选
(.*?|\n)*?
【讨论】:
永远不要使用(.*?|\n)*?
,除非你想以灾难性的回溯结束。【参考方案9】:
"."
通常不匹配换行符。大多数正则表达式引擎允许您添加S
-标志(也称为DOTALL
和SINGLELINE
)以使"."
也匹配换行符。
如果失败,您可以执行[\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)*)<foobar>
。
【讨论】:
不,不要那样做。如果您需要匹配包括行分隔符在内的任何内容,请使用 DOTALL(又名 /s 或 SingleLine)修饰符。 (.|\n) hack 不仅降低了正则表达式的效率,甚至不正确。至少,它应该匹配 \r(回车)和 \n(换行)。还有其他行分隔符,尽管很少使用。但如果你使用 DOTALL 标志,你就不必担心它们。 \R 是 Eclipse 中换行符的平台无关匹配项。 @opyate 您应该将此作为答案发布,因为这个小宝石非常有用。 你可以试试这个。它不会匹配内括号,还可以考虑可选的\r
.:((?:.|\r?\n)*)<foobar>
【参考方案16】:
解决办法:
使用模式修饰符sU
将在 PHP 中获得所需的匹配。
示例:
preg_match('/(.*)/sU', $content, $match);
来源:
Pattern Modifiers【讨论】:
第一个链接以某种方式重定向到www.facebook.com
(我已在hosts file 中阻止)。该链接是否损坏?
我猜所有者决定将其重定向到 Facebook 页面。我会删除它。【参考方案17】:
在语言中使用的上下文中,正则表达式作用于字符串,而不是行。所以你应该可以正常使用正则表达式,假设输入字符串有多行。
在这种情况下,给定的正则表达式将匹配整个字符串,因为存在“
基于行的正则表达式通常用于 egrep 之类的命令行。
【讨论】:
【参考方案18】:尝试:.*\n*.*<FooBar>
假设您也允许空白换行符。因为您允许任何字符,包括 <FooBar>
之前的任何字符。
【讨论】:
看起来不太对劲。为什么两次“.*
”?这可能适用于问题中的示例输入,但如果“我遇到了同样的问题,并以可能不是最好的方式解决了它,但它确实有效。我在进行真正的比赛之前替换了所有换行符:
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<Foobar></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
就是(<PercentComplete>)
。所以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 可视化正则表达式:
【讨论】:
以上是关于如何在正则表达式中匹配多行中的任何字符?的主要内容,如果未能解决你的问题,请参考以下文章