Regex [A-Z] не распознавать локальные символы - PullRequest
0 голосов
/ 12 мая 2018

Я проверил другие проблемы и прочитал их решения, они не работают. Я проверил регулярное выражение, которое работает с не локальными символами. Код - это просто найти любые заглавные буквы в строке и выполнить с ними некоторую процедуру. Например, minikŞeker bir kedi вернет kŞe, однако мой код не распознает Ş как букву в [A-Z]. Когда я пытаюсь re.LOCALE по запросу некоторых людей, я получаю ошибку ValueError: cannot use LOCALE flag with a str pattern, когда я использую re.UNICODE

import re
corp = "minikŞeker bir kedi"
pattern = re.compile(r"([\w]{1})()([A-Z]{1})", re.U)
corp = re.sub(pattern, r"\1 \3", corp)
print(corp)

Работает для minikSeker bir kedi, не работает для minikŞeker bir kedi и выдает ошибку для re.L. Ошибка, которую я получаю, ValueError: cannot use LOCALE flag with a str pattern Поиск ее привел к небольшим дискуссиям, но ничего полезного.

Ответы [ 2 ]

0 голосов
/ 12 мая 2018

Ответ abarnet великолепен, но если все, что вам нужно, это найти символы в верхнем регистре, str.isupper() работает без необходимости использования дополнительного модуля.

>>> foo = "minikŞeker bir kedi"
>>> for i, c in enumerate(foo):
...     if c.isupper():
...         print(foo[i-1:i+2])
...         break
... 
kŞe

или, возможно,

>>> foo = "minikŞeker bir kedi"
>>> ''.join((' ' if c.isupper() else '') + c for c in foo)
'minik Şeker bir kedi'
0 голосов
/ 12 мая 2018

Проблема в том, что Ş не находится в диапазоне [A-Z]. Этот диапазон является классом всех символов, чьи кодовые точки лежат U + 0040 и U + 005A (включительно). (Если бы вы использовали байтовый режим, все байты были бы в диапазоне от 0x40 до 0x5A.) И Ş - это U + 0153 (или, например, 0xAA в байтах, при условии latin2). Который не в этом диапазоне.

И использование локали не изменит этого. Как объясняет re.LOCALE, все, что он делает, это:

Сделать \ w, \ W, \ b, \ B и сопоставление без учета регистра зависимым от текущей локали.

Кроме того, вы почти никогда не хотите использовать re.LOCALE. Как говорят в документах:

Использование этого флага не рекомендуется, поскольку механизм локали очень ненадежен, он обрабатывает только одну «культуру» за раз и работает только с 8-битными локалями.

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

Если вы хотите работать со всеми сценариями, вам нужно создать класс из класса символов Unicode, например Lu для "всех заглавных букв". К сожалению, у re в Python нет механизма, позволяющего делать это напрямую. Вы можете создать гигантский класс из информации в unicodedata, но это довольно раздражает:

Lu = '[' + ''.join(chr(c) for c in range(0, 0x10ffff) 
                   if unicodedata.category(chr(c)) == 'Lu') + ']'

А потом:

pattern = re.compile(r"([\w]{1})()(" + Lu + r"{1})", re.U)

… или, может быть:

pattern = re.compile(rf"([\w]{{1}})()({Lu}{{1}})", re.U)

Но хорошая новость заключается в том, что одна из причин, по которой re не может указать классы Unicode, заключается в том, что долгое время планировалось заменить re новым модулем, поэтому многие предлагали новый функции для re были отклонены. Но хорошая новость заключается в том, что предполагаемый новый модуль доступен в виде сторонней библиотеки, regex. Он работает просто отлично и является почти полной заменой re; он просто улучшался слишком быстро, чтобы привязать его к более медленному графику выпуска Python. Если вы установите его, вы можете написать свой код следующим образом:

import regex
corp = "minikŞeker bir kedi"
pattern = regex.compile(r"([\w]{1})()(\p{Lu}{1})", re.U)
corp = regex.sub(pattern, r"\1 \3", corp)
print(corp)

Единственное изменение, которое я сделал, - заменить re на regex, а затем использовать \p{Lu} вместо [A-Z].

Конечно, существует множество других движков регулярных выражений, и многие из них также поддерживают классы символов Юникода. Большинство из тех, которые следуют некоторым вариациям в том же синтаксисе \p. (Все они скопировали его из Perl, но детали отличаются - например, идея regex о классах Unicode происходит из модуля unicodedata, в то время как PCRE и PCRE2 пытаются быть как можно ближе к Perl, и тд.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...