【问题标题】:How do I match any character across multiple lines in a regular expression?如何在正则表达式中匹配多行中的任何字符?
【发布时间】:2025-11-30 07:00:02
【问题描述】:

例如,这个正则表达式

(.*)<FooBar>

将匹配:

abcde<FooBar>

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

abcde
fghij<FooBar>

【问题讨论】:

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

标签: regex multiline


【解决方案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 正则表达式库使用。

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

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

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

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

基于 POSIX 的引擎

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

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

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

  • - 有多种解决方法。最精确但不是很安全的是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 -0pe 's/(.*)&lt;FooBar&gt;/$1/gs' &lt;&lt;&lt; "$str"-0 将整个文件吞入内存,-p 在应用-e 给出的脚本后打印文件)。请注意,使用 -000pe 将删除文件并激活“段落模式”,其中 Perl 使用连续换行符 (\n\n) 作为记录分隔符。
  • - grep -Poz '(?si)abc\K.*?(?=&lt;Foobar&gt;)' file。这里,z 启用文件 slurping,(?s) 启用 . 模式的 DOTALL 模式,(?i) 启用不区分大小写模式,\K 省略到目前为止匹配的文本,*? 是一个惰性量词,@ 987654421@ 匹配&lt;Foobar&gt; 之前的位置。
  • - pcregrep -Mi "(?si)abc\K.*?(?=&lt;Foobar&gt;)" fileM 在此处启用文件 slurping)。注意pcregrep 是 macOS grep 用户的一个很好的解决方案。

See demos.

非 POSIX 引擎

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

  • - 使用 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;

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

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

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

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

  • - 使用 RegexOption.DOT_MATCHES_ALL : "(.*)&lt;FooBar&gt;".toRegex(RegexOption.DOT_MATCHES_ALL)

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

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

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

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

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

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

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

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

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

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

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

  • - 使用 (?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);
        

        来源:

        【讨论】:

        • 第一个链接以某种方式重定向到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)
          【解决方案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 可视化正则表达式:

                  【讨论】:

                    最近更新 更多