Регулярные выражения Mathematica для строк Unicode

Это был увлекательный опыт отладки. Можете ли вы найти разницу между следующими двумя строками?

StringReplace["–", RegularExpression@"[\\s\\S]" -> "abc"]
StringReplace["-", RegularExpression@"[\\s\\S]" -> "abc"]

Они делают очень разные вещи, когда вы их оцениваете. Оказывается, это потому, что заменяемая строка в первой строке состоит из юникодного тире, в отличие от простого старого тире ascii во второй строке.

В случае строки Unicode регулярное выражение не соответствует. Я имел в виду, что регулярное выражение «[\s\S]» означает «соответствие любому символу (включая новую строку)», но Mathematica, по-видимому, рассматривает его как «соответствие любому символу ascii».

Как я могу исправить регулярное выражение, чтобы первая строка выше оценивалась так же, как вторая? В качестве альтернативы, есть ли фильтр asciify, который я могу сначала применить к строкам?

PS: В документации Mathematica говорится, что сопоставление строковых шаблонов построено на основе Perl-совместимой библиотеки регулярных выражений (http://pcre.org), поэтому проблема, с которой я столкнулся, может быть не связана с Mathematica.


person dreeves    schedule 25.03.2010    source источник
comment
Я не знаю, почему этот старый вопрос стал активным, но проблема, похоже, была решена в версии 10, теперь оба работают. Unicode en dash имеет ключ \: 2013 в mathematica, кстати.   -  person agentp    schedule 16.03.2017


Ответы (3)


Вот функция asciify, которую я сначала использовал в качестве обходного пути:

f[s_String] := s
f[x_] := FromCharacterCode[x]

asciify[s_String] := 
  StringJoin[f /@ (ToCharacterCode[s] /. x_?(#>255&) :> "&"<>ToString[x]<>";")]

Затем я понял, благодаря ответу @Isaac, что "." поскольку регулярное выражение, похоже, не имеет этой проблемы с юникодом. Из ответов на Ошибка в Mathematica: регулярное выражение применяется к очень длинной строке, я узнал, что "(.| \n)" опрометчиво, но это "(?s)". Рекомендовано. Поэтому я думаю, что лучшим решением является следующее:

StringReplace["–", RegularExpression@"(?s)." -> "abc"]
person dreeves    schedule 25.03.2010
comment
Интересно читать другие вопросы/ответы на вашем сайте. Учитывая то, что там есть, я склонен согласиться с тем, что "(?s).", вероятно, лучше, хотя, когда я читаю эти ответы, проблема может быть ограничена "(.|\n)*"*). - person Isaac; 25.03.2010

Я бы использовал StringExpression вместо RegularExpression. Это работает по желанию:

f[s_String] := StringReplace[s, _ -> "abc"]

В StringExpression Blank[] будет соответствовать чему угодно, включая символы, отличные от ASCII.

ИЗМЕНИТЬ в ответ на обновления версии: начиная с Mathematica 11.0.1, он выглядит как буквенные символы с кодами символов до 2^16 - 1 (что называется максимальным значением для < a href="http://reference.wolfram.com/language/ref/FromCharacterCode.html" rel="nofollow noreferrer">FromCharacterCode), результаты StringMatchQ[LetterCharacter] теперь совпадают с результатами LetterQ.

AllTrue[FromCharacterCode /@ Range[2^16 - 1], 
 LetterQ@# === StringMatchQ[#, LetterCharacter] &]
(* True *)
person Pillsy    schedule 26.03.2010
comment
Как отмечено в руководстве по работе со строковыми шаблонами [1] в разделе RegularExpression и StringExpression, шаблоны строк _ и RegularExpression["(?s)."] эквивалентны. [1] reference.wolfram.com/mathematica/tutorial/ - person Michael Pilat; 26.03.2010

Использование "(.|\n)" для ввода в RegularExpression, кажется, работает для меня. Шаблон соответствует . (любому символу, отличному от новой строки) или \n (символу новой строки).

person Isaac    schedule 25.03.2010