那是不是;堆栈溢出错误“;Java正则表达式总是意味着需要优化正则表达式?

那是不是;堆栈溢出错误“;Java正则表达式总是意味着需要优化正则表达式?,java,regex,stack-overflow,Java,Regex,Stack Overflow,要读取CSV文件,我有以下Java正则表达式: Pattern csvline = Pattern.compile("((([^\\\"]|\\\"\\\")+|\\\"([^\\\"]|\\\"\\\")+\\\"))*", Pattern.DOTALL); 这个表达式通过了。但是,在运行它时,它总是抛出一个StackOverflowError 经过一些研究,我发现解决方案是用 Pattern csvline = Pattern.compile("((([^\\\"]|\\\"\\\")++

要读取CSV文件,我有以下Java正则表达式:

Pattern csvline = Pattern.compile("((([^\\\"]|\\\"\\\")+|\\\"([^\\\"]|\\\"\\\")+\\\"))*", Pattern.DOTALL);
这个表达式通过了。但是,在运行它时,它总是抛出一个
StackOverflowError

经过一些研究,我发现解决方案是用

Pattern csvline = Pattern.compile("((([^\\\"]|\\\"\\\")++|\\\"([^\\\"]|\\\"\\\")++\\\"))*", Pattern.DOTALL);
这里我用所有格量词代替贪婪量词。在这种情况下,它也被认为是一种优化


我的问题是,因为Java无法处理多个回溯(它会消耗堆栈空间,我认为一个好的引擎不应该这样),所以每当您看到正则表达式导致的
stackoverflower错误时,您应该考虑以某种方式进行优化以减少回溯?

Java抛出
StackOverflowerError
显示匹配是通过递归调用在内部完成的。这是不好的,但它本身也是好的,因为它表明了正则表达式的潜在问题

回溯地狱是由这样一个事实引起的:在另一个有限多匹配
*
((A++B))*
(这是正则表达式的形式)中进行有限多匹配
+


通常,如果您可以编写一个不需要回溯且不需要堆栈的非正则表达式解决方案(如括号匹配问题),那么您可以编写一个带有所有格量词的正则表达式(在普通量词之后添加额外的
+
),执行相同的任务,因为所有格量词不(允许)回溯,这类似于在非正则表达式解决方案中所做的操作。

是的,Java正则表达式引擎已损坏。它使用回溯,因此可以支持回溯引用,因此具有与所有类似perl的正则表达式引擎相同的病态指数空间/时间问题。您是对的,它可能会分析表达式以确定它实际上是正则的,并使用您期望的多项式空间/时间算法

在这种情况下,我总是建议使用级联正则表达式,最好是通过,尽管如果坚持使用2级或3级,手工操作不会太痛苦。更重要的是,如果您使用lexer,它将更易于维护、编写和调试

其思想是通过重复应用简单正则表达式来解析该行。在您的情况下,第一个字段标识下一个字段的开始;第二个标识字段的结尾(捕获内容);第三个检查“下一个字段”;重复一遍


这些标记与使用JFlex识别的3个标记几乎相同。唯一的区别是字段分隔符标记非常简单,手动操作时可能会将其包含在“字段结束”正则表达式中。

只是好奇。。。这个正则表达式是否支持类似于
word1、word2、“word3和word4”
?为什么还需要额外的括号?相同的正则表达式:
([^\\\”]\\\\“\\\”+\\\”([^\\\”]\\\\“\\\”+\\”*
@OscarMederos是的,这只是故事的一部分。此表达式仅用于确定当前行是否为“真实”行的一部分。如果引用的字段包含换行符,“当前”行需要与以下行合并。因此,算法是在附加处理之前重建整条线。@pstr您完全正确。这可能是之前对表达式进行优化的结果。这是我在上面提出的声明的示例:。问题是在单词的粒度上检查一个句子是否是完整句子的子序列(单词的顺序必须遵循,但单词不需要构成完整句子的连续部分)。