10

在下面的代码中,如果字符串 s 被附加为 10 或 20,000 个字符,则 Mathematica 内核 seg 错误。

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 错误的想法也会受到赞赏。

4

3 回答 3

8

Mathematica 使用 PCRE 语法,因此它确实具有/saka DOTALLaka Singleline 修饰符,您只需(?s)在要应用它的表达式部分之前添加修饰符。

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

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

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

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

由于@AlanMoore 解释的原因,它也应该更快一些

于 2010-02-14T16:36:02.550 回答
4

优化正则表达式的最佳方法取决于 Mathematica 正则表达式引擎的内部结构,但(.|\\n)*正如@Simon 所提到的,我肯定会摆脱 . 这不仅仅是交替——尽管在交替中每个选项都与一个字符完全匹配,这几乎总是一个错误;这就是字符类的用途。但是,当您匹配每个字符(因为括号)时,您也会捕获它,只是在匹配下一个字符时将其丢弃。

快速浏览 Mathematica 正则表达式文档并没有发现任何类似/s(Singleline or DOTALL) 修饰符的东西,所以我推荐使用旧的 JavaScript 备用,[\\s\\S]*-- 匹配任何空白或非空白的任何内容。此外,将锚点添加到正则表达式的末尾可能会有所帮助:$

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

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

于 2010-02-13T22:45:57.117 回答
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."
于 2010-04-22T21:27:01.670 回答