Ошибка в Mathematica: регулярное выражение применялось к очень длинной строке

В следующем коде, если к строке s добавляется что-то вроде 10 или 20 тысяч символов, происходит сбой сегментации ядра 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 будут оценены.


person dreeves    schedule 13.02.2010    source источник
comment
+1 за то, что я отправил отчет об ошибке и ...   -  person Pascal Cuoq    schedule 13.02.2010
comment
Возможно, это не связано, но другие движки регулярных выражений (например, движок Java) имеют проблемы с регулярными выражениями формы (x|y)*, которая есть в вашем регулярном выражении: см. bugs.sun.com/bugdatabase/view_bug.do?bug_id=6337993.   -  person Simon Nickerson    schedule 13.02.2010
comment
Возможно, есть настройка, похожая на /s PREG, которая позволяет точкам соответствовать новым строкам? Это может немного упростить. Опять же, я понятия не имею о Mathematica, но в других языках это не было бы сделано с помощью регулярного выражения; вы можете просто разделить на MAGIC_STRING и взять первый результат.   -  person Max Shawabkeh    schedule 13.02.2010
comment
@Max: Очевидно, что функция StringSplit Mathematica работает с регулярными выражениями, поэтому вы можете использовать (?m)^.*MAGIC_STRING, чтобы разделение происходило в начале строки. О, и посмотрите ответ @Michael относительно /s/m и /i).   -  person Alan Moore    schedule 14.02.2010


Ответы (3)


Mathematica использует синтаксис PCRE, поэтому у него есть модификатор /s aka DOTALL aka Singleline, вы просто добавляете модификатор (?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.

person Michael Pilat    schedule 14.02.2010
comment
Думаю, я просмотрел немного слишком быстро. :-/ Вы тестировали это регулярное выражение с (?m)^ впереди? Похоже, это должно ускорить его немного больше. - person Alan Moore; 14.02.2010

Лучший способ оптимизировать регулярное выражение зависит от внутреннего устройства механизма регулярных выражений Mathematica, но я бы определенно избавился от (.|\\n)*, как упоминал @Simon. Это не просто чередование — хотя почти всегда бывает ошибкой иметь чередование, в котором каждая альтернатива соответствует ровно одному символу; вот для чего нужны классы персонажей. Но вы также захватываете каждый символ, когда вы его сопоставляете (из-за круглых скобок), только для того, чтобы отбросить его, когда вы сопоставляете следующий символ.

Быстрый просмотр документации по регулярным выражениям Mathematica не обнаруживает ничего похожего на модификатор /s (Singleline или DOTALL), поэтому я рекомендую старый резервный JavaScript, [\\s\\S]* -- соответствует всему, что является пробелом, или чему-либо, что не является пробелом. Кроме того, может помочь добавить якорь $ в конец регулярного выражения:

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

Но лучшим вариантом, вероятно, будет вообще не использовать регулярные выражения. Я не вижу здесь ничего, что требовало бы их, и, вероятно, было бы намного проще и эффективнее использовать обычные функции Mathematica для работы со строками.

person Alan Moore    schedule 13.02.2010
comment
Это было чрезвычайно поучительно. Спасибо! - person dreeves; 14.02.2010

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."
person J D    schedule 22.04.2010
comment
или там, где важна правильность. Mathematica — это получение правильных ответов. Это серьезное и необоснованное обвинение. - person gdelfino; 23.04.2010
comment
Спасибо за репликацию этого на другом языке; это полезно. (Хотя я склонен согласиться с gdelfino по поводу вашей преамбулы.) - person dreeves; 23.04.2010
comment
@gdelfino: Просто посмотрите на нелепые ошибки в основных версиях Mathematica, которые они поставляют. Например, в системе Mathematica 7.0.0 практически каждое преобразование Фурье, выполненное функцией Fourier, давало неверный ответ, поскольку отбрасывало мнимые компоненты. flyingfrogblog.blogspot.com/2009/05/ - person J D; 23.04.2010
comment
@dreeves: Ну, я использую Mathematica уже более 10 лет, и это очень весело, но каждый раз, когда я пытался проделать с ней какую-либо серьезную работу, Mathematica получала все ответы неправильно. Когда я защитил докторскую диссертацию, у меня было четыре основных символьных вывода, и Mathematica (v4) давала неправильные ответы для всех из них, а также имела серьезную ошибку в ListConvolve, которая незаметно искажала все мои численные вычисления. Абсурдна идея, что Mathematica предназначена для получения правильных ответов. - person J D; 23.04.2010