В разделах программирование и языковое
Андрей Баксаляр  :: 10 мар 2016, в 23:09

Работая с греческим алфавитом в Unicode, в Python 3.4.3, наткнулся на странный баг (по всей видимости, здесь косяк как Пайтона, так и таблиц Юникода). Если у вас интерпретатор версии 3.4-3.5, то проблема легко воспроизводится следующим образом:

'ΰ'.upper().lower() == 'ΰ'

Интерпретатор неожиданно выдаст вам False. Несмотря на то, что по логике вещей ΰ == ΰ. После преобразований регистра из-за проблемы с правилами меппинга Unicode, Пайтон подменяет ΰ на ΰ:

'ΰ'.upper().lower().encode('utf-8')
b'\xcf\x85\xcc\x88\xcc\x81'
'ΰ'.encode('utf-8')
b'\xce\xb0'

Как видно, исходный символ и символ, возвращаемый lower() — разные, второй возвращается с другим диакритическим знаком, что даже визуально заметно в редакторе (да и на странице видно невооруженным глазом), хотя так быть точно не должно.

ΰu → ΰu

При дальнейшем гуглении оказалось, что о данном глюке уже было сообщено. И сообщение пайтоновского багтрекера даже успели закрыть с формулировкой «исправлено» более четырех лет назад, перед выпуском Python 3.3, только вот баг остался даже в свежей версии Python 3.5.1 (а также 3.4.3), а вот во второй ветке (проверено на Python 2.7.6 от 22 июня 2015) он исправлен.

Воспроизведение бага в Python 2.7.6, 3.4.3 и 3.5.1

Кроме того, баг оказался более обширным, чем думалось изначально. В конце статьи (под катом) вы найдете таблицу символов-оборотней, меняющихся с двойным изменением регистра.

Например…

(
unicodedata.name('Ω'.upper().lower()),
unicodedata.name('Ω')
)

... неожиданно возвращает:

('GREEK SMALL LETTER OMEGA', 'OHM SIGN')

Написал сообщение в тикет, будем ждать ответа. Также попробовал обновить Пайтон до самой последней версии, однако это не помогло.

P.S. Интересно, что данная проблема затрагивает и NodeJS версий 5.6.0 (стабильная) и 5.8.0 (самая свежая):

Воспроизведение бага в NodeJS 5.6

Воспроизведение бага в NodeJS 5.8

Однако в консоли браузера (Firefox 44.0.2) проблема уже не воспроизводится:

Воспроизведение бага в JavaScript внутри браузера Firefox 44.0.2

P.P.S. В качестве костыльного решения в Пайтоне предлагается использовать такой подход:

unicodedata.normalize('NFC', 'ΰ'.upper().lower()) == 'ΰ'
True
Исходник.upper().lower()Снова .upper()
µ (0xb5)Μ (0x39c)μ (0x3bc)Μ (0x39c)
ß (0xdf)SS (0x5353)ss (0x7373)SS (0x5353)
İ (0x130) (0x69307) (0x49307) (0x69307)
ı (0x131)I (0x49)i (0x69)I (0x49)
ʼn (0x149)ʼN (0x2bc4e)ʼn (0x2bc6e)ʼN (0x2bc4e)
ſ (0x17f)S (0x53)s (0x73)S (0x53)
ǰ (0x1f0) (0x4a30c) (0x6a30c) (0x4a30c)
ͅ (0x345)Ι (0x399)ι (0x3b9)Ι (0x399)
ΐ (0x390)Ϊ́ (0x399308301)ΐ (0x3b9308301)Ϊ́ (0x399308301)
ΰ (0x3b0)Ϋ́ (0x3a5308301)ΰ (0x3c5308301)Ϋ́ (0x3a5308301)
ς (0x3c2)Σ (0x3a3)σ (0x3c3)Σ (0x3a3)
ϐ (0x3d0)Β (0x392)β (0x3b2)Β (0x392)
ϑ (0x3d1)Θ (0x398)θ (0x3b8)Θ (0x398)
ϕ (0x3d5)Φ (0x3a6)φ (0x3c6)Φ (0x3a6)
ϖ (0x3d6)Π (0x3a0)π (0x3c0)Π (0x3a0)
ϰ (0x3f0)Κ (0x39a)κ (0x3ba)Κ (0x39a)
ϱ (0x3f1)Ρ (0x3a1)ρ (0x3c1)Ρ (0x3a1)
ϴ (0x3f4)θ (0x3b8)Θ (0x398)θ (0x3b8)
ϵ (0x3f5)Ε (0x395)ε (0x3b5)Ε (0x395)
և (0x587)ԵՒ (0x535552)եւ (0x565582)ԵՒ (0x535552)
(0x1e96) (0x48331) (0x68331) (0x48331)
(0x1e97) (0x54308) (0x74308) (0x54308)
(0x1e98) (0x5730a) (0x7730a) (0x5730a)
(0x1e99) (0x5930a) (0x7930a) (0x5930a)
(0x1e9a) (0x412be) (0x612be) (0x412be)
(0x1e9b) (0x1e60) (0x1e61) (0x1e60)
(0x1e9e)ß (0xdf)SS (0x5353)ss (0x7373)
(0x1f50)Υ̓ (0x3a5313)ὐ (0x3c5313)Υ̓ (0x3a5313)
(0x1f52)Υ̓̀ (0x3a5313300)ὒ (0x3c5313300)Υ̓̀ (0x3a5313300)
(0x1f54)Υ̓́ (0x3a5313301)ὔ (0x3c5313301)Υ̓́ (0x3a5313301)
(0x1f56)Υ̓͂ (0x3a5313342)ὖ (0x3c5313342)Υ̓͂ (0x3a5313342)
(0x1f80)ἈΙ (0x1f08399)ἀι (0x1f003b9)ἈΙ (0x1f08399)
(0x1f81)ἉΙ (0x1f09399)ἁι (0x1f013b9)ἉΙ (0x1f09399)
(0x1f82)ἊΙ (0x1f0a399)ἂι (0x1f023b9)ἊΙ (0x1f0a399)
(0x1f83)ἋΙ (0x1f0b399)ἃι (0x1f033b9)ἋΙ (0x1f0b399)
(0x1f84)ἌΙ (0x1f0c399)ἄι (0x1f043b9)ἌΙ (0x1f0c399)
(0x1f85)ἍΙ (0x1f0d399)ἅι (0x1f053b9)ἍΙ (0x1f0d399)
(0x1f86)ἎΙ (0x1f0e399)ἆι (0x1f063b9)ἎΙ (0x1f0e399)
(0x1f87)ἏΙ (0x1f0f399)ἇι (0x1f073b9)ἏΙ (0x1f0f399)
(0x1f90)ἨΙ (0x1f28399)ἠι (0x1f203b9)ἨΙ (0x1f28399)
(0x1f91)ἩΙ (0x1f29399)ἡι (0x1f213b9)ἩΙ (0x1f29399)
(0x1f92)ἪΙ (0x1f2a399)ἢι (0x1f223b9)ἪΙ (0x1f2a399)
(0x1f93)ἫΙ (0x1f2b399)ἣι (0x1f233b9)ἫΙ (0x1f2b399)
(0x1f94)ἬΙ (0x1f2c399)ἤι (0x1f243b9)ἬΙ (0x1f2c399)
(0x1f95)ἭΙ (0x1f2d399)ἥι (0x1f253b9)ἭΙ (0x1f2d399)
(0x1f96)ἮΙ (0x1f2e399)ἦι (0x1f263b9)ἮΙ (0x1f2e399)
(0x1f97)ἯΙ (0x1f2f399)ἧι (0x1f273b9)ἯΙ (0x1f2f399)
(0x1fa0)ὨΙ (0x1f68399)ὠι (0x1f603b9)ὨΙ (0x1f68399)
(0x1fa1)ὩΙ (0x1f69399)ὡι (0x1f613b9)ὩΙ (0x1f69399)
(0x1fa2)ὪΙ (0x1f6a399)ὢι (0x1f623b9)ὪΙ (0x1f6a399)
(0x1fa3)ὫΙ (0x1f6b399)ὣι (0x1f633b9)ὫΙ (0x1f6b399)
(0x1fa4)ὬΙ (0x1f6c399)ὤι (0x1f643b9)ὬΙ (0x1f6c399)
(0x1fa5)ὭΙ (0x1f6d399)ὥι (0x1f653b9)ὭΙ (0x1f6d399)
(0x1fa6)ὮΙ (0x1f6e399)ὦι (0x1f663b9)ὮΙ (0x1f6e399)
(0x1fa7)ὯΙ (0x1f6f399)ὧι (0x1f673b9)ὯΙ (0x1f6f399)
(0x1fb2)ᾺΙ (0x1fba399)ὰι (0x1f703b9)ᾺΙ (0x1fba399)
(0x1fb3)ΑΙ (0x391399)αι (0x3b13b9)ΑΙ (0x391399)
(0x1fb4)ΆΙ (0x386399)άι (0x3ac3b9)ΆΙ (0x386399)
(0x1fb6)Α͂ (0x391342)ᾶ (0x3b1342)Α͂ (0x391342)
(0x1fb7)Α͂Ι (0x391342399)ᾶι (0x3b13423b9)Α͂Ι (0x391342399)
(0x1fbe)Ι (0x399)ι (0x3b9)Ι (0x399)
(0x1fc2)ῊΙ (0x1fca399)ὴι (0x1f743b9)ῊΙ (0x1fca399)
(0x1fc3)ΗΙ (0x397399)ηι (0x3b73b9)ΗΙ (0x397399)
(0x1fc4)ΉΙ (0x389399)ήι (0x3ae3b9)ΉΙ (0x389399)
(0x1fc6)Η͂ (0x397342)ῆ (0x3b7342)Η͂ (0x397342)
(0x1fc7)Η͂Ι (0x397342399)ῆι (0x3b73423b9)Η͂Ι (0x397342399)
(0x1fd2)Ϊ̀ (0x399308300)ῒ (0x3b9308300)Ϊ̀ (0x399308300)
(0x1fd3)Ϊ́ (0x399308301)ΐ (0x3b9308301)Ϊ́ (0x399308301)
(0x1fd6)Ι͂ (0x399342)ῖ (0x3b9342)Ι͂ (0x399342)
(0x1fd7)Ϊ͂ (0x399308342)ῗ (0x3b9308342)Ϊ͂ (0x399308342)
(0x1fe2)Ϋ̀ (0x3a5308300)ῢ (0x3c5308300)Ϋ̀ (0x3a5308300)
(0x1fe3)Ϋ́ (0x3a5308301)ΰ (0x3c5308301)Ϋ́ (0x3a5308301)
(0x1fe4)Ρ̓ (0x3a1313)ῤ (0x3c1313)Ρ̓ (0x3a1313)
(0x1fe6)Υ͂ (0x3a5342)ῦ (0x3c5342)Υ͂ (0x3a5342)
(0x1fe7)Ϋ͂ (0x3a5308342)ῧ (0x3c5308342)Ϋ͂ (0x3a5308342)
(0x1ff2)ῺΙ (0x1ffa399)ὼι (0x1f7c3b9)ῺΙ (0x1ffa399)
(0x1ff3)ΩΙ (0x3a9399)ωι (0x3c93b9)ΩΙ (0x3a9399)
(0x1ff4)ΏΙ (0x38f399)ώι (0x3ce3b9)ΏΙ (0x38f399)
(0x1ff6)Ω͂ (0x3a9342)ῶ (0x3c9342)Ω͂ (0x3a9342)
(0x1ff7)Ω͂Ι (0x3a9342399)ῶι (0x3c93423b9)Ω͂Ι (0x3a9342399)
(0x2126)ω (0x3c9)Ω (0x3a9)ω (0x3c9)
(0x212a)k (0x6b)K (0x4b)k (0x6b)
(0x212b)å (0xe5)Å (0xc5)å (0xe5)
(0xfb00)FF (0x4646)ff (0x6666)FF (0x4646)
(0xfb01)FI (0x4649)fi (0x6669)FI (0x4649)
(0xfb02)FL (0x464c)fl (0x666c)FL (0x464c)
(0xfb03)FFI (0x464649)ffi (0x666669)FFI (0x464649)
(0xfb04)FFL (0x46464c)ffl (0x66666c)FFL (0x46464c)
(0xfb05)ST (0x5354)st (0x7374)ST (0x5354)
(0xfb06)ST (0x5354)st (0x7374)ST (0x5354)
(0xfb13)ՄՆ (0x544546)մն (0x574576)ՄՆ (0x544546)
(0xfb14)ՄԵ (0x544535)մե (0x574565)ՄԵ (0x544535)
(0xfb15)ՄԻ (0x54453b)մի (0x57456b)ՄԻ (0x54453b)
(0xfb16)ՎՆ (0x54e546)վն (0x57e576)ՎՆ (0x54e546)
(0xfb17)ՄԽ (0x54453d)մխ (0x57456d)ՄԽ (0x54453d)

Пока комментариев нет, будь первым!

Войти через...


Это даст читателю возможность голоса, комментария, создания закладки, и даже написания поста, не говоря о множестве других мелких ништяков.

Популярное


Соациализируемся


Также найти меня можно в других злачных местах:

Все еще использую электронную почту:
andreybaksalyar@ya.ru