Mathematica中的错误:正则表达式应用于非常长的字符串

时间:2010-02-13 14:39:58

标签: regex string wolfram-mathematica

在下面的代码中,如果字符串s附加为10或2万个字符,则Mathematica内核会出错。

s = "This is the first line.
MAGIC_STRING
Everything after this line should get removed.
12345678901234567890123456789012345678901234567890123456789012345678901234567890
12345678901234567890123456789012345678901234567890123456789012345678901234567890
12345678901234567890123456789012345678901234567890123456789012345678901234567890
12345678901234567890123456789012345678901234567890123456789012345678901234567890
12345678901234567890123456789012345678901234567890123456789012345678901234567890
...";

s = StringReplace[s, RegularExpression@"(^|\\n)[^\\n]*MAGIC_STRING(.|\\n)*"->""]

我认为这主要是Mathematica的错,我已经提交了一份错误报告,如果得到回复,我会跟进。但我也想知道我是否以愚蠢/低效的方式做这件事。即使不是,也应该赞赏解决Mathematica错误的想法。

3 个答案:

答案 0 :(得分:8)

Mathematica使用PCRE语法,因此它确实具有/s又名DOTALL又名单行修饰符,您只需将(?s)修饰符添加到您希望它所在的表达式部分之前应用。

请参阅此处的RegularExpression文档:(展开标有“更多信息”的部分)
http://reference.wolfram.com/mathematica/ref/RegularExpression.html

  

以下所有正则表达式元素的设置选项:
  (?i)将大写和小写视为等效(忽略大小写)
  (?m)使^和$匹配行的开始和结束(多行模式)
  (?s)允许。匹配换行符
  (?-c)未设置选项

这个修改后的输入不会让Mathematica 7.0.1崩溃(原来的),使用长度为15,000个字符的字符串,产生与表达式相同的输出:

s = StringReplace[s,RegularExpression@".*MAGIC_STRING(?s).*"->""]

@AlanMoore解释

的原因也应该快一点

答案 1 :(得分:4)

优化正则表达式的最佳方法取决于Mathematica的正则表达式引擎的内部结构,但我绝对会像@Simon提到的那样摆脱(.|\\n)*。这不仅仅是交替 - 尽管每个选项只匹配一个字符的交替几乎总是错误的;这就是角色类的用途。但是当你匹配它时,你也会捕获每个角色(因为括号),只有当你匹配下一个角色时才把它扔掉。

对Mathematica正则表达式文档的快速扫描没有出现像/s(单行或DOTALL)修饰符,所以我建议旧的JavaScript待机,[\\s\\S]* - 匹配任何< em>是空格或不是空格的任何内容。此外,将$锚点添加到正则表达式的末尾可能会有所帮助:

"(^|\\n)[^\\n]*MAGIC_STRING[\\s\\S]*$"

但你最好的选择可能就是根本不使用正则表达式。我在这里看不到任何需要它们的东西,使用Mathematica的普通字符串操作函数可能会更容易也更有效。

答案 2 :(得分:2)

Mathematica是一个伟大的执行玩具,但我建议不要尝试做任何严肃的事情,如长字符串的正则表达式或对大量数据的任何计算(或正确性很重要)。使用经过试验和测试的东西Visual F#2010需要5毫秒和一行代码才能获得正确答案而不会崩溃:

> let str =
    "This is the first line.\nMAGIC_STRING\nEverything after this line should get removed." +
      String.replicate 2000 "0123456789";;
val str : string =
  "This is the first line.
MAGIC_STRING
Everything after this li"+[20022 chars]

> open System.Text.RegularExpressions;;
> #time;;
--> Timing now on

> (Regex "(^|\\n)[^\\n]*MAGIC_STRING(.|\\n)*").Replace(str, "");;
Real: 00:00:00.005, CPU: 00:00:00.015, GC gen0: 0, gen1: 0, gen2: 0
val it : string = "This is the first line."