Ошибка в Mathematica: регулярное выражение применяется к очень длинной строке
В следующем коде, если строка s добавлена как 10 или 20 тысяч символов, ядро Seg Mathematica отключается.
s = "This is the first line.
MAGIC_STRING
Everything after this line should get removed.
12345678901234567890123456789012345678901234567890123456789012345678901234567890
12345678901234567890123456789012345678901234567890123456789012345678901234567890
12345678901234567890123456789012345678901234567890123456789012345678901234567890
12345678901234567890123456789012345678901234567890123456789012345678901234567890
12345678901234567890123456789012345678901234567890123456789012345678901234567890
...";
s = StringReplace[s, [email protected]"(^|\\n)[^\\n]*MAGIC_STRING(.|\\n)*"->""]
Я думаю, что это прежде всего ошибка Mathematica, и я представил отчет об ошибке и буду следить за этим, если я получу ответ. Но мне также интересно, делаю ли я это глупо/неэффективно. И даже если нет, идеи для работы с ошибкой Mathematica будут оценены.
Ответы
Ответ 1
Mathematica использует синтаксис PCRE, поэтому он имеет модификатор /s
aka DOTALL
aka Singleline, вы просто добавляете модификатор (?s)
перед частью выражения, в котором вы хотите применить.
См. документацию RegularExpression здесь: (развернуть раздел с надписью "Дополнительная информация" )
http://reference.wolfram.com/mathematica/ref/RegularExpression.html
Следующие параметры для всех элементов регулярного выражения, которые следуют за ними:
(?i)
обрабатывать прописные и строчные буквы как эквивалентные (игнорировать регистр)
(?m)
make ^ и $match начало и конец строк (многострочный режим)
(?s)
разрешить. для соответствия новостям | (?-c)
отменять параметры
Этот измененный ввод не разбивает Mathematica 7.0.1 для меня (оригинал сделал), используя строку длиной 15 000 символов, создавая тот же результат, что и ваше выражение:
s = StringReplace[s,[email protected]".*MAGIC_STRING(?s).*"->""]
Он также должен быть немного быстрее по причинам, описанным @AlanMoore
Ответ 2
Лучший способ оптимизировать регулярное выражение зависит от внутренних компонентов механизма регулярного выражения Mathematica, но я определенно избавился бы от (.|\\n)*
, как упоминал @Simon. Это не просто чередование - хотя почти всегда бывает ошибкой иметь чередование, в котором каждая альтернатива соответствует ровно одному персонажу; для каких классов символов. Но вы также захватываете каждого персонажа, когда вы его сопоставляете (из-за круглых скобок), только чтобы выбросить его, когда вы сопоставляете следующий символ.
Быстрое сканирование документов регулярного выражения Mathematica не вызывает ничего похожего на модификатор /s
(Singleline или DOTALL), поэтому я рекомендую старый режим ожидания JavaScript [\\s\\S]*
- сопоставить все, что является пробелом, или что-либо, что не является пробелом. Кроме того, это может помочь добавить якорь $
в конец регулярного выражения:
"(^|\\n)[^\\n]*MAGIC_STRING[\\s\\S]*$"
Но ваш лучший вариант, вероятно, не будет использовать регулярные выражения вообще. Я не вижу ничего здесь, что их требует, и, вероятно, было бы намного проще, а также более эффективно использовать обычные функции манипуляции Mathematica.
Ответ 3
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."