Ошибка в Mathematica: регулярное выражение применяется к очень длинной строке - PullRequest
10 голосов
/ 13 февраля 2010

В следующем коде, если к строке 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 приветствуются.

Ответы [ 3 ]

8 голосов
/ 14 февраля 2010

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

4 голосов
/ 14 февраля 2010

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

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

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

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

2 голосов
/ 23 апреля 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."
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...