我想匹配用三重"
-引号引起来的字符串,这些字符串可能包含换行符,并且除了开头和结尾之外都不包含任何"""
-子字符串。
有效的例子:
"""foo
bar "baz" blah"""
无效的示例:
"""foo bar """ baz"""
我尝试使用以下正则表达式(作为Java
String
文字):"(?m)\"\"\"(?:[^\"]|(?:\"[^\"])|(?:\"\"[^\"]))*\"\"\""
它似乎可以在一些简短的例子中发挥作用。但是,在较长的示例中,例如在由
hello world
组成的包含数千行的字符串上,它给了我StackOverflowError
。Scala代码段重现错误
import java.util.regex.{Pattern, Matcher}
val text = "\"" * 3 + "hello world \n" * 1000 + "\"" * 3
val p = Pattern.compile("(?m)\"\"\"(?:[^\"]|(?:\"[^\"])|(?:\"\"[^\"]))*\"\"\"")
println(p.matcher("\"\"\" foo bar baz \n baz bar foo \"\"\"").lookingAt())
println(p.matcher(text).lookingAt())
(注意:本地测试,Scastie超时;或者将1000减少到较小的数字?)。
产生相同错误的Java代码段
import java.util.regex.Pattern;
import java.util.regex.Matcher;
class RegexOverflowMain {
public static void main(String[] args) {
StringBuilder bldr = new StringBuilder();
bldr.append("\"\"\"");
for (int i = 0; i < 1000; i++) {
bldr.append("hello world \n");
}
bldr.append("\"\"\"");
String text = bldr.toString();
Pattern p = Pattern.compile("(?m)\"\"\"(?:[^\"]|(?:\"[^\"])|(?:\"\"[^\"]))*\"\"\"");
System.out.println(p.matcher("\"\"\" foo bar baz \n baz bar foo \"\"\"").lookingAt());
System.out.println(p.matcher(text).lookingAt());
}
}
题
知道如何使此“堆栈安全”的想法,即有人可以找到接受相同语言但在馈入Java regex API时不产生
StackOverflowError
的正则表达式吗?我不在乎解决方案是在Scala还是Java(或其他)中,只要使用相同的基础Java regex库即可。
最佳答案
解决方案:使用否定提前查找来基本上找到以"""
开头和"""
结束并且包含不包含"""
内容的字符串
作为纯正则表达式:^"""((?!""")[\s\S])*"""$
由于Java转义了正则表达式:"^\"\"\"((?!\"\"\")[\\s\\S])*\"\"\"$
”\s\S
包括换行符(基本上是.
+换行符或带有单个行标志的.
)
应该在没有多行标志的情况下使用此命令,以便^
和$
匹配字符串的开头和结尾,而不是行的开头和结尾。
否则这:""" ab"""abc"""abc """
会匹配
我也以此为参考来排除"""
:Regular expression to match a line that doesn't contain a word?