2016-04-21 8 views
2

Что такое предполагаемая семантика для диапазонов символов в регулярных выражениях, если одна или обе конечные точки диапазона находятся вне BMP? Я заметил, что следующий вход ведет себя отличается в Python 2.7 и 3.5:Семантика Python для диапазонов Unicode, включающих астральные плоскости

import re 
bool(re.match(u"[\u1000-\U00021111]", "\u1234")) 

В моем 2.7 я получаю False, в 3.5 я получаю True. Последнее имеет смысл для меня. Первое, возможно, связано с \U00021111, представленным суррогатной парой \ud844\udd11, но даже тогда я не понимаю его, так как \u1000-\ud844 должен включать \u1234 просто отлично.

  • Это указано где-то?
  • Это намеренное поведение?
  • Это зависит только от версии Python, а также от флагов времени компиляции относительно UTF-16 и UTF-32?
  • Есть ли способ добиться последовательного поведения без различий в различиях?
  • Если различия в случае неизбежны, то какие условия являются условиями?

ответ

3

Просто используйте префикс u с входной строки сказать Python это строка Unicode:

>>> bool(re.match(u"[\u1000-\U00021111]", u"\u1234")) # <= See u"\u1234" 
True 

В Python 2.7, вам необходимо декодировать строки в Unicode каждый раз, когда вы их обработки. В Python 3 все строки Unicode по умолчанию, и это указано в docs.

+1

Спасибо! Я чувствую себя глупо, что не заметил этого. Однако основная проблема остается: 'bool (re.match (u" [\ u1000- \ U00021111] ", u" \ ueeee "))' все еще дает разные результаты.Я знаю, что это плохой стиль для редактирования вопроса, как только он был дан ответ, таким образом, что ответ больше не применяется. Вы согласны с тем, что я это сделаю, или я должен опубликовать новый вопрос? – MvG

+0

Пожалуйста, проверьте [эту демонстрационную версию Python 2.7 IDEONE] (https://ideone.com/p9Jsgv). 'print (bool (re.match (u" [\ u1000- \ U00021111] ", u" \ ueeee ")))' печатает 'True'. Ваш Python 2.7 должен быть настроен для ввода Unicode (см. '# - * - coding: utf-8 - * -' pragma). –

+2

@ WiktorStribiżew '#coding: utf8' ничего не делает в этом случае. Он объявляет кодировку самого исходного файла, и в этом источнике нет не-ASCII-символов. –

2

Вот что я выяснил до сих пор.

PEP 261, принятый для Python 2.2, представил флаг времени компиляции для создания поддержки Unicode либо с использованием узкого представления UTF-16, либо с широким представлением символов UTF-32. Проверьте hex(sys.maxunicode) или len(u'\U00'), чтобы отличить их во время работы: узкие сборки сообщают максимум 0xffff и длину 2, шириной не более 0x10ffff и длиной 1. PEP 393 для Python 3.3 скрывает детали реализации строки в Юникоде, делая все строки похожими на UTF-32 (не тратя впустую столько места, если это необходимо). Таким образом, узкие построения до 3.3 будут разлагать кодовые точки на астральных плоскостях на суррогатные пары и обрабатывать отдельные суррогаты независимо как для построения регулярного выражения, так и для строки, к которой нужно сопоставить. Или, по крайней мере, я не мог найти никаких указаний об обратном.

Как заметил Wiktor, мой пример был довольно глупым, поскольку я забыл префикс u для второго строкового литерала. Поэтому Python 2 будет анализировать это не как escape-последовательность, а как байтовую строку. Это объясняет, почему это выглядело так, как если бы кодовое число не было включено в этот диапазон даже после того, как были приняты во внимание суррогатные пары.

Что касается предполагаемого поведения: поскольку Python 3.3 отличие от типа сборки должно устареть. Рассмотрение каждого кодека как единицы, независимо от плоскости, должно быть направлением для Python 3. Но обратная совместимость в узких строках создает противоречивую цель для более старых версий.

+0

Python 3.3 использует гибкое представление Unicode (я не думаю, что он скрывает реализацию больше, чем, например, большая сборка python делает - это противоположность: утечка абстракции для символов без BMP в узких строках python). Непонятно, почему модуль регулярных выражений не может обрабатывать суррогатные пары. – jfs

+0

@ J.F.Sebastian: Я согласен, что нет причин, по которым суррогатные пары * не могут обрабатываться модулем re, но мое наблюдение указывает на то, что * не обрабатываются *. Я предполагаю, что сначала это было не просто, а наоборот. Многие другие языки на основе UTF-16 делают то же самое: Java, JavaScript, ... Я не уверен, что понимаю ваш аргумент об утечке абстракции. Но я думаю, что не должно быть разницы между 3.3+ и широким <3.3 на уровне Python, хотя на уровне модуля расширения будут различия. Это ты имел в виду? – MvG

+2

Мы согласны, но есть крошечное крошечное различие: вы говорите: * «Python 3.3 ** скрывает ** детали реализации» *, я говорю, что узкая сборка python ** предоставляет ** ее (недостаточную) реализацию. Результат тот же, разница заключается в том, что вы добавляете акцент/стресс. «Утечка абстракции» означает, что узкая сборка Python не учитывает представление о том, что строка Unicode является последовательностью кодов Unicode в Python (один кодовый код Unicode может быть представлен как два кодовых пункта (суррогатная пара)). – jfs