Linux сұрыптауы жолдарды қалай сұрыптайды

Кіріспе

Барлығы мекенжай ақпаратын біріктіретін қысқа сценарийден басталды электрондық пошта жіберу парағын пайдаланушылар тізімінен алынған қызметкерлер, қызметкерлердің лауазымдары кадр бөлімінің дерекқорынан алынған. Екі тізім де Юникод мәтіндік файлдарына экспортталды UTF-8 және Unix жолының аяқталуымен сақталады.

Мазмұны mail.txt

Иванов Андрей;[email protected]

Мазмұны buhg.txt

Иванова Алла;маляр
Ёлкина Элла;крановщица
Иванов Андрей;слесарь
Абаканов Михаил;маляр

Біріктіру үшін файлдар Unix пәрмені арқылы сұрыпталды сорт және Unix бағдарламасының енгізуіне жіберіледі Қосылу, ол қатемен күтпеген жерден сәтсіз аяқталды:

$> sort buhg.txt > buhg.srt
$> sort mail.txt > mail.srt
$> join buhg.srt mail.srt > result
join: buhg.srt:4: is not sorted: Иванов Андрей;слесарь

Сұрыптау нәтижесін көзбен қарау, жалпы алғанда, сұрыптау дұрыс екенін көрсетті, бірақ ерлер мен әйелдердің фамилиялары сәйкес келген жағдайда, әйелдер еркектерден бұрын келеді:

$> sort buhg.txt
Абаканов Михаил;маляр
Ёлкина Элла;крановщица
Иванова Алла;маляр
Иванов Андрей;слесарь

Юникодтағы сұрыптау ақауы немесе сұрыптау алгоритміндегі феминизм көрінісі сияқты. Біріншісі, әрине, орындырақ.

Әзірге оны бір жаққа қояйық Қосылу және назар аударыңыз сорт. Мәселені ғылыми покинг арқылы шешуге тырысайық. Алдымен, жергілікті тілді келесіден өзгертейік en_US туралы ru_RU. Сұрыптау үшін ортаның айнымалы мәнін орнату жеткілікті болады LC_COLLATE, бірақ біз уақытты ұсақ-түйекке жұмсамаймыз:

$> LANG=ru_RU.UTF-8 sort buhg.txt
Абаканов Михаил;маляр
Ёлкина Элла;крановщица
Иванова Алла;маляр
Иванов Андрей;слесарь

Ештеңе өзгерген жоқ.

Файлдарды бір байт кодтауға қайта кодтауға тырысайық:

$> iconv -f UTF-8 -t KOI8-R buhg.txt 
 | LANG=ru_RU.KOI8-R sort 
 | iconv -f KOI8-R -t UTF8

Тағы да ештеңе өзгерген жоқ.

Сіз ештеңе істей алмайсыз, сіз Интернеттен шешім іздеуіңіз керек. Орыс фамилиялары туралы тікелей ештеңе жоқ, бірақ басқа сұрыптау оғаштықтары туралы сұрақтар бар. Мысалы, мәселе мынада: unix сұрыптауы '-' (сызықша) таңбаларын көрінбейтін ретінде қарастырады. Қысқасы, «ab», «aa», «ac» жолдары «aa», «ab», «ac» болып сұрыпталады.

Жауап барлық жерде стандартты: бағдарламашы тілін пайдаланыңыз «C» және сіз бақытты боласыз. Тырысып көрейік:

$> LANG=C sort buhg.txt
Ёлкина Элла;крановщица
Абаканов Михаил;маляр
Иванов Андрей;слесарь
Иванова Алла;адвокат

Бір нәрсе өзгерді. Йолкина бір жерде сырғып кетсе де, Ивановтар дұрыс ретпен тізілді. Бастапқы мәселеге оралайық:

$> LANG=C sort buhg.txt > buhg.srt
$> LANG=C sort mail.txt > mail.srt
$> LANG=C join buhg.srt mail.srt > result

Интернет уәде еткендей, ол қатесіз жұмыс істеді. Бұл бірінші қатардағы Йолкинаға қарамастан.

Мәселе шешілген сияқты, бірақ бұл жағдайда басқа орыс кодтауын қолданып көрейік - Windows CP1251:

$> iconv -f UTF-8 -t CP1251 buhg.txt 
 | LANG=ru_RU.CP1251 sort 
 | iconv -f CP1251 -t UTF8 

Сұрыптау нәтижесі, таңқаларлық, жергілікті тілмен сәйкес келеді «C», және бүкіл мысал сәйкесінше қатесіз жұмыс істейді. Мистицизмнің бір түрі.

Мен бағдарламалаудағы мистицизмді ұнатпаймын, өйткені ол әдетте қателерді жасырады. Біз оның қалай жұмыс істейтінін мұқият қарастыруымыз керек. сорт және ол не әсер етеді? LC_COLLATE .

Соңында мен сұрақтарға жауап беруге тырысамын:

  • әйел фамилиялары неге дұрыс емес сұрыпталған?
  • неге LANG=ru_RU.CP1251 эквивалент болып шықты LANG=C
  • неге сорт и Қосылу сұрыпталған жолдардың реті туралы әртүрлі идеялар
  • неге менің барлық мысалдарымда қателер бар?
  • соңында жолдарды өз қалауыңыз бойынша қалай сұрыптауға болады

Юникодта сұрыптау

Бірінші аялдама №10 техникалық есеп болады Юникодты сұрыптау алгоритмі сайтта unicode.org. Баяндамада көптеген техникалық детальдар бар, сондықтан негізгі ойларды қысқаша мазмұндауға рұқсат етіңіздер.

салыстыру — «салыстыру» жолдары кез келген сұрыптау алгоритмінің негізі болып табылады. Алгоритмдердің өзі әртүрлі болуы мүмкін («көпіршік», «біріктіру», «жылдам»), бірақ олардың барлығы пайда болу ретін анықтау үшін жұп жолдарды салыстыруды пайдаланады.

Табиғи тілде жолдарды сұрыптау өте күрделі мәселе. Ең қарапайым бір байт кодтауларында да, әліпбидегі әріптердің реті, тіпті ағылшын латын әліпбиінен біршама өзгеше болса да, енді бұл әріптер кодталған сандық мәндердің ретімен сәйкес келмейді. Сонымен неміс алфавитінде әріп Ö арасында тұрады О и P, және кодтауда CP850 арасына түседі ÿ и Ü.

Сіз белгілі бір кодтаудан абстракциялауға және Юникодта жасалғандай белгілі бір ретпен орналастырылған «идеалды» әріптерді қарастыруға болады. Кодтаулар UTF8, UTF16 немесе бір байт KOI8-R (Егер Юникодтың шектеулі жиыны қажет болса) әріптердің әртүрлі сандық көрсетілімдерін береді, бірақ негізгі кестенің бірдей элементтеріне сілтеме жасайды.

Символдар кестесін нөлден құрсақ та, оған әмбебап таңбалар тәртібін тағайындай алмаймыз екен. Бір әріптерді қолданатын әртүрлі ұлттық алфавиттерде бұл әріптердің реті әртүрлі болуы мүмкін. Мысалы, француз тілінде Æ лигатура болып саналады және жол ретінде сұрыпталады AE. Норвег тілінде Æ кейін орналасқан бөлек әріп болады Z. Айтпақшы, лигатуралардан басқа сияқты Æ Бірнеше таңбамен жазылған әріптер бар. Сонымен чех алфавитінде әріп бар Ch, арасында орналасқан H и I.

Әліпбидегі айырмашылықтардан басқа, сұрыптауға әсер ететін басқа да ұлттық дәстүрлер бар. Атап айтқанда, үлкен және кіші әріптерден тұратын сөздер сөздікте қандай ретпен болуы керек деген сұрақ туындайды? Сұрыптауға тыныс белгілерін қолдану да әсер етуі мүмкін. Испан тілінде сұраулы сөйлемнің басында төңкерілген сұрақ белгісі қолданылады (Сізге музыка ұнайды ма?). Бұл жағдайда сұраулы сөйлемдерді әліпбиден тыс жеке кластерге топтастыру емес, басқа тыныс белгілері бар жолдарды қалай сұрыптау керек екені анық?

Мен еуропалық тілдерден мүлдем өзгеше тілдердегі жолдарды сұрыптау туралы тоқталмаймын. Оңнан солға немесе жоғарыдан төменге жазу бағыты бар тілдерде жолдардағы таңбалар оқу ретімен сақталады, тіпті әліпбилік емес жазу жүйелерінде де жолдарды таңба бойынша ретке келтірудің өзіндік тәсілдері бар екенін ескеріңіз. . Мысалы, иероглифтерді стиль бойынша ретке келтіруге болады (Қытай таңбаларының пернелері) немесе айтылуы бойынша. Шынымды айтсам, эмодзилерді қалай орналастыру керектігін білмеймін, бірақ сіз олар үшін бірдеңе ойлап таба аласыз.

Жоғарыда аталған мүмкіндіктердің негізінде Юникод кестелері негізінде жолдарды салыстыруға қойылатын негізгі талаптар тұжырымдалған:

  • жолдарды салыстыру код кестесіндегі символдардың орнына байланысты емес;
  • бір таңбаны құрайтын таңбалар тізбегі канондық түрге келтіріледі (A + жоғарғы шеңбер бірдей Å);
  • Жолдарды салыстыру кезінде символ жолдың контекстінде қарастырылады және қажет болған жағдайда оның көршілерімен бір салыстыру бірлігіне біріктіріледі (Ch чех тілінде) немесе бірнешеге бөлінеді (Æ француз тілінде);
  • барлық ұлттық ерекшеліктер (алфавит, бас/кіші, тыныс белгілері, жазу түрлерінің реті) ретті (эмодзи) қолмен тағайындауға дейін конфигурациялануы керек;
  • Салыстыру сұрыптау үшін ғана емес, сонымен қатар көптеген басқа жерлерде де маңызды, мысалы, жолдар ауқымын көрсету үшін ({A... z} орнын ауыстыру bash);
  • салыстыру өте жылдам жасалуы керек.

Сонымен қатар, есеп авторлары алгоритм әзірлеушілерге сенбеуі керек салыстыру қасиеттерін тұжырымдады:

  • салыстыру алгоритмі әр тіл үшін таңбалардың бөлек жинағын талап етпеуі керек (орыс және украин тілдерінде кириллица таңбаларының көпшілігі ортақ);
  • салыстыру Юникод кестелеріндегі таңбалардың ретіне сүйенбеу керек;
  • жолдың салмағы жолдың атрибуты болмауы керек, өйткені әртүрлі мәдени контексттердегі бір жолдың салмағы әртүрлі болуы мүмкін;
  • Жол салмақтары біріктіру немесе бөлу кезінде өзгеруі мүмкін ( x < y соны ұстанбайды xz < yz);
  • бірдей салмақтары бар әртүрлі жолдар сұрыптау алгоритмі тұрғысынан тең деп саналады. Мұндай жолдардың қосымша ретін енгізу мүмкін, бірақ ол өнімділікті төмендетуі мүмкін;
  • Қайталанатын сұрыптау кезінде салмақтары бірдей жолдарды ауыстыруға болады. Мықтылық жолды салыстыру алгоритмінің қасиеті емес, белгілі бір сұрыптау алгоритмінің қасиеті болып табылады (алдыңғы абзацты қараңыз);
  • Мәдени дәстүрлер нақтыланған/өзгеретіндіктен сұрыптау ережелері уақыт өте өзгеруі мүмкін.

Сондай-ақ, салыстыру алгоритмі өңделетін жолдардың семантикасы туралы ештеңе білмейтіні қарастырылған. Осылайша, тек сандардан тұратын жолдарды сандармен салыстыруға болмайды, ал ағылшын атауларының тізімдерінде мақала (Битлз, The).

Барлық көрсетілген талаптарды қанағаттандыру үшін кестені сұрыптаудың көп деңгейлі (шын мәнінде төрт деңгейлі) алгоритмі ұсынылған.

Бұрын жолдағы таңбалар канондық пішінге келтіріліп, салыстыру бірліктеріне топтастырылған. Әрбір салыстыру бірлігіне бірнеше салыстыру деңгейіне сәйкес келетін бірнеше салмақтар тағайындалады. Салыстыру бірліктерінің салмақтары реттелген жиындардың элементтері болып табылады (бұл жағдайда бүтін сандар), оларды көп немесе аз салыстыруға болады. Ерекше мағына ЕЛДЕРІЛМЕГЕН (0x0) сәйкес салыстыру деңгейінде бұл бірлік салыстыруға қатыспайтынын білдіреді. Жолдарды салыстыру сәйкес деңгейлердің салмақтарын пайдалана отырып, бірнеше рет қайталануы мүмкін. Әрбір деңгейде екі қатардағы салыстыру бірліктерінің салмақтары бір-бірімен дәйекті түрде салыстырылады.

Әртүрлі ұлттық дәстүрлерге арналған алгоритмді әртүрлі іске асыруда коэффициенттердің мәндері әртүрлі болуы мүмкін, бірақ Юникод стандарты салмақтардың негізгі кестесін қамтиды - «Әдепкі Юникодты сұрыптау элементтері кестесі» (DUCET). Мен айнымалы мәнді орнатуды атап өткім келеді LC_COLLATE шын мәнінде жолды салыстыру функциясында салмақ кестесін таңдаудың көрсеткіші болып табылады.

Салмақ коэффициенттері DUCET төмендегідей реттелген:

  • бірінші деңгейде барлық әріптер бір регистрге қысқартылады, диакритика жойылады, тыныс белгілері (барлығы емес) еленбейді;
  • екінші деңгейде тек диакритика ескеріледі;
  • үшінші деңгейде тек жағдай ғана есепке алынады;
  • төртінші деңгейде тыныс белгілері ғана ескеріледі.

Салыстыру бірнеше өтуде жүреді: біріншіден, бірінші деңгейдің коэффициенттері салыстырылады; егер салмақтар сәйкес келсе, онда екінші деңгейдегі салмақтармен қайталап салыстыру жүргізіледі; содан кейін үшінші және төртінші болуы мүмкін.

Салыстыру жолдарда әртүрлі салмақтары бар сәйкес салыстыру бірліктері болғанда аяқталады. Барлық төрт деңгейде бірдей салмақтары бар жолдар бір-біріне тең деп саналады.

Бұл алгоритм (көптеген қосымша техникалық мәліметтермен) №10 есептің атауын берді - «Юникодты салыстыру алгоритмі» (БАУ).

Міне, біздің мысалдағы сұрыптау әрекеті біршама айқынырақ болады. Оны Юникод стандартымен салыстыру жақсы болар еді.

Іске асыруды сынау үшін БАУ арнайы бар викторина, қолдану салмақтар файлы, іске асыру DUCET. Таразы файлында күлкілі нәрселердің барлық түрлерін таба аласыз. Мысалы, махжонг пен еуропалық доминолардың реті, сондай-ақ карталар палубасындағы костюмдердің реті бар (символ 1F000 және одан әрі). Карточкалық костюмдер bridge - PCBT ережелері бойынша орналастырылады, ал костюмдегі карталар Т, 2,3, XNUMX... К тізбегі бойынша орналасады.

Жолдардың сәйкес дұрыс сұрыпталғанын қолмен тексеру DUCET бұл өте жалықтырады, бірақ, бақытымызға орай, Юникодпен жұмыс істеуге арналған кітапхананың үлгілі іске асырылуы бар - «Юникодқа арналған халықаралық компоненттер«(ICU).

Осы кітапхананың сайтында әзірленген IBM, демонстрациялық беттер бар, соның ішінде жолды салыстыру алгоритмі беті. Біз сынақ жолдарымызды әдепкі параметрлермен енгіземіз және міне, біз тамаша ресейлік сұрыптауды аламыз.

Абаканов Михаил;маляр
Ёлкина Элла;крановщица
Иванов Андрей;слесарь
Иванова Алла;адвокат

Айтпақшы, веб-сайт ICU Тыныс белгілерін өңдеу кезінде салыстыру алгоритмінің нақтылануын табуға болады. Мысалдарда Салыстыру жиі қойылатын сұрақтар апостроф пен сызықша еленбейді.

Юникод бізге көмектесті, бірақ оғаш мінез-құлық себептерін іздеңіз сорт в Linux басқа жерге баруға тура келеді.

glibc ішінде сұрыптау

Утилитаның бастапқы кодтарын жылдам көру сорт -дан GNU Core Utils утилитаның өзінде локализация айнымалының ағымдағы мәнін басып шығаруға келетінін көрсетті LC_COLLATE отладка режимінде іске қосылғанда:

$ sort --debug buhg.txt > buhg.srt
sort: using ‘en_US.UTF8’ sorting rules

Жолды салыстыру стандартты функцияның көмегімен орындалады strcoll, яғни қызықтының бәрі кітапханада glibc.

туралы уики жоба glibc жолды салыстыруға арналған бір абзац. Осы тармақтан мынаны түсінуге болады glibc сұрыптау бізге бұрыннан белгілі алгоритмге негізделген БАУ (Юникодты сұрыптау алгоритмі) және/немесе оған жақын стандартта ISO 14651 (Халықаралық жолды ретке келтіру және салыстыру). Соңғы стандартқа келетін болсақ, бұл сайтта екенін атап өткен жөн standards.iso.org ISO 14651 ресми түрде жалпыға қолжетімді деп жарияланды, бірақ сәйкес сілтеме жоқ бетке әкеледі. Google стандарттың электронды көшірмесін жүз еуроға сатып алуды ұсынатын ресми сайттарға сілтемелері бар бірнеше беттерді қайтарады, бірақ іздеу нәтижелерінің үшінші немесе төртінші бетінде де тікелей сілтемелер бар. PDF. Жалпы, стандарт іс жүзінде айырмашылығы жоқ БАУ, бірақ оны оқу қызықсызырақ, өйткені онда жолды сұрыптаудың ұлттық ерекшеліктерінің нақты мысалдары жоқ.

туралы ең қызықты ақпарат уики сілтемесі бар еді қателерді бақылау құралы жылы жолды салыстыруды жүзеге асыруды талқылаумен glibc. Талқылаудан мұны білуге ​​болады glibc жолдарды салыстыру үшін қолданылады ISOжеке үстел Жалпы үлгілер кестесі (CTT), мекен-жайын өтініште табуға болады A стандарт ISO 14651. 2000-2015 жылдар аралығында бұл кестеде glibc техникалық қызмет көрсетушісі болмады және стандарттың қазіргі нұсқасынан (кем дегенде сыртқы жағынан) айтарлықтай ерекшеленді. 2015 жылдан бастап 2018 жылға дейін кестенің жаңа нұсқасына бейімделу өтті, енді сізде кестенің жаңа нұсқасын нақты өмірде кездестіруге мүмкіндік бар (CentOS 8) және ескі (CentOS 7).

Енді бізде алгоритм және көмекші кестелер туралы барлық ақпарат бар, біз бастапқы мәселеге оралып, орыс тілінде жолдарды қалай дұрыс сұрыптау керектігін түсінеміз.

ISO 14651 / 14652

Бізді қызықтыратын кестенің бастапқы коды CTT дистрибуциялардың көпшілігінде Linux каталогта орналасқан /usr/share/i18n/locales/. Кестенің өзі файлда iso14651_t1_common. Содан кейін бұл файл директивасы iso14651_t1_common көшіру файлға енгізілген iso14651_t1, ол өз кезегінде ұлттық файлдарға, соның ішінде en_US и ru_RU. Көптеген дистрибуцияларда Linux барлық бастапқы файлдар негізгі орнатуға кіреді, бірақ олар жоқ болса, дистрибутивтен қосымша буманы орнатуға тура келеді.

Құрылым файла iso14651_t1 атауларды құрудың анық емес ережелері бар өте егжей-тегжейлі болып көрінуі мүмкін, бірақ егер сіз оған қарасаңыз, бәрі өте қарапайым. Құрылым стандартта сипатталған ISO 14652, оның көшірмесін веб-сайттан жүктеп алуға болады open-std.org. Файл пішімінің басқа сипаттамасын оқуға болады спецификациялар POSIX от OpenGroup. Стандартты оқуға балама ретінде функцияның бастапқы кодын зерттеуге болады салыстыру_оқу в glibc/locale/programs/ld-collate.c.

Файл құрылымы келесідей көрінеді:

Әдепкі бойынша, таңба шығу таңбасы ретінде пайдаланылады және # таңбасынан кейінгі жолдың соңы түсініктеме болып табылады. Екі таңбаны да қайта анықтауға болады, бұл кестенің жаңа нұсқасында орындалады:

escape_char /
comment_char %

Файлда пішімдегі таңбалауыштар болады немесе (Қайда x - он алтылық сан). Бұл кодтаудағы Юникод код нүктелерінің он алтылық көрінісі UCS-4 (UTF-32). Бұрыштық жақшалардағы барлық басқа элементтер (соның ішінде , және сол сияқтылар) контекстен тыс мағынасы аз қарапайым жол тұрақтылары болып саналады.

Жол LC_COLLATE келесі жолдарды салыстыруды сипаттайтын деректер басталатынын айтады.

Біріншіден, салыстыру кестесіндегі салмақтар үшін атаулар және таңба комбинациялары үшін атаулар көрсетіледі. Жалпы айтқанда, атаулардың екі түрі екі түрлі нысанға жатады, бірақ нақты файлда олар араласады. Салмақ атаулары түйінді сөз арқылы көрсетіледі жинақтау белгісі (салыстырмалы таңба), өйткені салыстыру кезінде салмағы бірдей Юникод таңбалары баламалы таңбалар болып саналады.

Ағымдағы файлды қайта қараудағы бөлімнің жалпы ұзындығы шамамен 900 жолды құрайды. Мен атаулардың еріктілігін және синтаксистің бірнеше түрін көрсету үшін бірнеше жерден мысалдар тарттым.

LC_COLLATE

collating-symbol <RES-1>
collating-symbol <BLK>
collating-symbol <MIN>
collating-symbol <WIDE>
...
collating-symbol <ARABIC>
collating-symbol <ETHPC>
collating-symbol <OSMANYA>
...
collating-symbol <S1D000>..<S1D35F>
collating-symbol <SFFFF> % Guaranteed largest symbol value. Keep at end of this list
...
collating-element <U0413_0301> from "<U0413><U0301>"
collating-element <U0413_0341> from "<U0413><U0341>"

  • жинақтау белгісі жолды тіркейді ОСМАЯ таразы атауларының кестесінде
  • жинақтау белгісі .. префикстен тұратын атаулар тізбегін тіркейді S және он алтылық сандық жұрнақ 1D000 қарай 1D35F.
  • FFFF в жинақтау белгісі он алтылық жүйеде үлкен таңбасыз бүтін санға ұқсайды, бірақ бұл жай ғана ұқсас болуы мүмкін атау
  • аты кодтаудағы код нүктесін білдіреді UCS-4
  • жинақтаушы элемент бастап " Юникод нүктелерінің жұбына жаңа атауды тіркейді.

Салмақтардың атаулары анықталғаннан кейін нақты салмақтар көрсетіледі. Салыстыру үшін тек үлкеннен аз қатынастар маңызды болғандықтан, салмақтар тізім атауларының қарапайым тізбегі арқылы анықталады. Алдымен «жеңіл» салмақтар, содан кейін «ауыр» салмақтар тізімделеді. Еске сала кетейін, әрбір Юникод таңбасына төрт түрлі салмақ тағайындалады. Мұнда олар бір реттелген реттілікке біріктірілген. Теориялық тұрғыдан кез келген символдық атауды төрт деңгейдің кез келгенінде қолдануға болады, бірақ түсініктемелер әзірлеушілер атауларды деңгейлерге ойша бөлетінін көрсетеді.

% Symbolic weight assignments

% Third-level weight assignments
<RES-1>
<BLK>
<MIN>
<WIDE>
...
% Second-level weight assignments
<BASE>
<LOWLINE> % COMBINING LOW LINE
<PSILI> % COMBINING COMMA ABOVE
<DASIA> % COMBINING REVERSED COMMA ABOVE
...
% First-level weight assignments
<S0009> % HORIZONTAL TABULATION 
<S000A> % LINE FEED
<S000B> % VERTICAL TABULATION
...
<S0434> % CYRILLIC SMALL LETTER DE
<S0501> % CYRILLIC SMALL LETTER KOMI DE
<S0452> % CYRILLIC SMALL LETTER DJE
<S0503> % CYRILLIC SMALL LETTER KOMI DJE
<S0453> % CYRILLIC SMALL LETTER GJE
<S0499> % CYRILLIC SMALL LETTER ZE WITH DESCENDER
<S0435> % CYRILLIC SMALL LETTER IE
<S04D7> % CYRILLIC SMALL LETTER IE WITH BREVE
<S0454> % CYRILLIC SMALL LETTER UKRAINIAN IE
<S0436> % CYRILLIC SMALL LETTER ZHE

Соңында, нақты салмақтар кестесі.

Салмақ бөлімі түйінді сөз жолдарымен қоршалған тапсырыс_бастау и тапсырыс_соңы. Қосымша опциялар тапсырыс_бастау салыстырудың әрбір деңгейінде қай бағытта жолдар сканерленетінін анықтаңыз. Әдепкі параметр болып табылады алға. Бөлімнің денесі символдық кодты және оның төрт салмағын қамтитын жолдардан тұрады. Таңба коды таңбаның өзімен, код нүктесімен немесе бұрын анықталған символдық атаумен ұсынылуы мүмкін. Салмақтарды символдық атауларға, кодтық нүктелерге немесе таңбалардың өздеріне де беруге болады. Егер код нүктелері немесе таңбалар пайдаланылса, олардың салмағы код нүктесінің сандық мәнімен бірдей болады (Юникод кестесіндегі орын). Анық көрсетілмеген таңбалар (менің түсінгенім) Юникод кестесіндегі орынға сәйкес келетін негізгі салмағы бар кестеге тағайындалған болып саналады. Арнайы салмақ мәні Елемеу сәйкес салыстыру деңгейінде таңба еленбейді дегенді білдіреді.

Таразылардың құрылымын көрсету үшін мен өте айқын үш үзіндіні таңдадым:

  • толығымен еленбейтін кейіпкерлер
  • алғашқы екі деңгейдегі үш санына тең таңбалар
  • кирилл әліпбиінің басталуы, онда диакритика жоқ, сондықтан негізінен бірінші және үшінші деңгейлер бойынша сұрыпталады.

order_start forward;forward;forward;forward,position
<U0000> IGNORE;IGNORE;IGNORE;IGNORE % NULL (in 6429)
<U0001> IGNORE;IGNORE;IGNORE;IGNORE % START OF HEADING (in 6429)
<U0002> IGNORE;IGNORE;IGNORE;IGNORE % START OF TEXT (in 6429)
...
<U0033> <S0033>;<BASE>;<MIN>;<U0033> % DIGIT THREE
<UFF13> <S0033>;<BASE>;<WIDE>;<UFF13> % FULLWIDTH DIGIT THREE
<U2476> <S0033>;<BASE>;<COMPAT>;<U2476> % PARENTHESIZED DIGIT THREE
<U248A> <S0033>;<BASE>;<COMPAT>;<U248A> % DIGIT THREE FULL STOP
<U1D7D1> <S0033>;<BASE>;<FONT>;<U1D7D1> % MATHEMATICAL BOLD DIGIT THREE
...
<U0430> <S0430>;<BASE>;<MIN>;<U0430> % CYRILLIC SMALL LETTER A
<U0410> <S0430>;<BASE>;<CAP>;<U0410> % CYRILLIC CAPITAL LETTER A
<U04D1> <S04D1>;<BASE>;<MIN>;<U04D1> % CYRILLIC SMALL LETTER A WITH BREVE
<U0430_0306> <S04D1>;<BASE>;<MIN>;<U04D1> % CYRILLIC SMALL LETTER A WITH BREVE
...
<U0431> <S0431>;<BASE>;<MIN>;<U0431> % CYRILLIC SMALL LETTER BE
<U0411> <S0431>;<BASE>;<CAP>;<U0411> % CYRILLIC CAPITAL LETTER BE
<U0432> <S0432>;<BASE>;<MIN>;<U0432> % CYRILLIC SMALL LETTER VE
<U0412> <S0432>;<BASE>;<CAP>;<U0412> % CYRILLIC CAPITAL LETTER VE
...
order_end

Енді мақаланың басынан бастап мысалдарды сұрыптауға оралуға болады. Тұтқа салмақ кестесінің осы бөлігінде жатыр:

<U0020> IGNORE;IGNORE;IGNORE;<U0020> % SPACE
<U0021> IGNORE;IGNORE;IGNORE;<U0021> % EXCLAMATION MARK
<U0022> IGNORE;IGNORE;IGNORE;<U0022> % QUOTATION MARK
...

Бұл кестеде тыныс белгілері кестеден қойылғанын көруге болады ASCII (бос орынды қоса) жолдарды салыстыру кезінде әрдайым дерлік еленбейді. Жалғыз ерекшелік - сәйкес позициялардағы тыныс белгілерін қоспағанда, барлығына сәйкес келетін сызықтар. Салыстыру алгоритміне арналған мысалдағы жолдар (сұрыптаудан кейін) келесідей көрінеді:

АбакановМихаилмаляр
ЁлкинаЭллакрановщица
ИвановаАлламаляр
ИвановАндрейслесарь

Масштаб кестесінде орыс тілінде бас әріптер кіші әріптерден кейін келетінін ескерсек (үшінші деңгейде қарағанда ауыр ), сұрыптау мүлдем дұрыс көрінеді.

Айнымалы мәнді орнату кезінде LC_COLLATE=C байт-байт салыстыруды көрсететін арнайы кесте жүктеледі

static const uint32_t collseqwc[] =
{
  8, 1, 8, 0x0, 0xff,
  /* 1st-level table */
  6 * sizeof (uint32_t),
  /* 2nd-level table */
  7 * sizeof (uint32_t),
  /* 3rd-level table */
  L'x00', L'x01', L'x02', L'x03', L'x04', L'x05', L'x06', L'x07',
  L'x08', L'x09', L'x0a', L'x0b', L'x0c', L'x0d', L'x0e', L'x0f',

...
  L'xf8', L'xf9', L'xfa', L'xfb', L'xfc', L'xfd', L'xfe', L'xff'
};

Юникодта Ё код нүктесі А-дан бұрын келетіндіктен, жолдар сәйкесінше сұрыпталады.

Мәтіндік және екілік кестелер

Әлбетте, жолды салыстыру өте кең таралған операция және кестені талдау CTT өте қымбат процедура. Кестеге қол жеткізуді оңтайландыру үшін ол командамен екілік пішінге жинақталады localdef.

команда localdef Параметрлер ретінде ұлттық сипаттамалар кестесі бар файлды қабылдайды (опция -i), онда барлық таңбалар Юникод нүктелерімен және Юникод нүктелері мен белгілі бір кодтау таңбалары арасындағы сәйкестік файлы (опция) -f). Жұмыстың нәтижесінде соңғы параметрде көрсетілген атаумен тіл үшін екілік файлдар жасалады.

glibc екі екілік файл пішімін қолдайды: «дәстүрлі» және «заманауи».

Дәстүрлі пішім тіл атауы ішкі каталогтың аты екенін білдіреді /usr/lib/locale/. Бұл ішкі каталог екілік файлдарды сақтайды LC_COLLATE, LC_CTYPE, LC_TIME және т.б. Файл LC_IDENTIFICATION тілдің ресми атауын (каталог атауынан басқаша болуы мүмкін) және түсініктемелерді қамтиды.

Қазіргі пішім барлық тілдерді бір мұрағатта сақтауды қамтиды /usr/lib/locale/locale-archive, ол қолданатын барлық процестердің виртуалды жадымен салыстырылады glibc. Қазіргі пішімдегі тіл атауы кейбір канонизацияға ұшырайды - кодтау атауларында тек кіші әріпке дейін қысқартылған сандар мен әріптер қалады. Сонымен ru_RU.KOI8-R, ретінде сақталады ru_RU.koi8r.

Енгізу файлдары ағымдағы каталогта да, каталогтарда да ізделеді /usr/share/i18n/locales/ и /usr/share/i18n/charmaps/ файлдар үшін CTT және сәйкесінше файлдарды кодтау.

Мысалы, команда

localedef -i ru_RU -f MAC-CYRILLIC ru_RU.MAC-CYRILLIC

файлды құрастырады /usr/share/i18n/locales/ru_RU кодтау файлын пайдалану /usr/share/i18n/charmaps/MAC-CYRILLIC.gz және нәтижені сақтаңыз /usr/lib/locale/locale-archive деген атпен ru_RU.maccyrillic

Егер айнымалы мәнді орнатсаңыз LANG = en_US.UTF-8 содан кейін glibc файлдар мен каталогтардың келесі тізбегінде жергілікті екілік файлдарды іздейді:

/usr/lib/locale/locale-archive
/usr/lib/locale/en_US.UTF-8/
/usr/lib/locale/en_US/
/usr/lib/locale/enUTF-8/
/usr/lib/locale/en/

Егер жергілікті тіл дәстүрлі және заманауи пішімдерде болса, онда басымдық қазіргіге беріледі.

Сіз пәрмен арқылы құрастырылған тілдер тізімін көре аласыз locale -a.

Салыстыру кестесін дайындау

Енді біліммен қаруланған сіз өзіңіздің идеалды жолды салыстыру кестесін жасай аласыз. Бұл кесте орыс әріптерін, соның ішінде Ё әрпін дұрыс салыстыру керек және сонымен бірге кестеге сәйкес тыныс белгілерін ескеруі керек. ASCII.

Жеке сұрыптау кестесін дайындау процесі екі кезеңнен тұрады: салмақтар кестесін өңдеу және оны пәрмен арқылы екілік пішінге құрастыру. localdef.

Салыстыру кестесі ең аз өңдеу шығындарымен пішімде түзетілуі үшін ISO 14652 Қолданыстағы кестенің салмақтарын реттеуге арналған бөлімдер берілген. Бөлім кілт сөзден басталады қайта тапсырыс беру және ауыстыру орындалатын позицияны көрсетеді. Бөлім сызықпен аяқталады қайта реттеу. Кестенің бірнеше бөлімін түзету қажет болса, онда әрбір осындай бөлім үшін бөлім жасалады.

Мен файлдардың жаңа нұсқаларын көшірдім iso14651_t1_common и ru_RU репозиторийден glibc менің үй каталогыма ~/.local/share/i18n/locales/ және бөлімді сәл өзгертті LC_COLLATE в ru_RU. Файлдардың жаңа нұсқалары менің нұсқама толық сәйкес келеді glibc. Егер файлдардың ескі нұсқаларын пайдаланғыңыз келсе, кестедегі символдық атауларды және ауыстыру басталатын орынды өзгертуіңіз керек.

LC_COLLATE
% Copy the template from ISO/IEC 14651
copy "iso14651_t1"
reorder-after <U000D>
<U0020> <S0020>;<BASE>;<MIN>;<U0020> % SPACE
<U0021> <S0021>;<BASE>;<MIN>;<U0021> % EXCLAMATION MARK
<U0022> <S0022>;<BASE>;<MIN>;<U0022> % QUOTATION MARK
...
<U007D> <S007D>;<BASE>;<MIN>;<U007D> % RIGHT CURLY BRACKET
<U007E> <S007E>;<BASE>;<MIN>;<U007E> % TILDE
reorder-end
END LC_COLLATE

Шын мәнінде, өрістерді өзгерту қажет болады LC_IDENTIFICATION олар жергілікті жерге нұсқау үшін ru_MY, бірақ менің мысалда бұл талап етілмеді, өйткені мен мұрағатты тілдерді іздеуден алып тастадым тіл мұрағаты.

сол localdef қалтадағы файлдармен айнымалы арқылы жұмыс істеді I18NPATH Кіріс файлдарын іздеу үшін қосымша каталог қосуға болады, ал екілік файлдарды сақтауға арналған каталог қиғаш сызықтары бар жол ретінде көрсетілуі мүмкін:

$> I18NPATH=~/.local/share/i18n localedef -i ru_RU -f UTF-8 ~/.local/lib/locale/ru_MY.UTF-8

POSIX деп болжайды ЖАЙ сіз қиғаш сызықтан бастап, жергілікті файлдары бар каталогтарға абсолютті жолдарды жаза аласыз, бірақ glibc в Linux барлық жолдар негізгі каталогтан есептеледі, оны айнымалы арқылы қайта анықтауға болады LOCPATH. Орнатқаннан кейін LOCPATH=~/.local/lib/locale/ локализацияға қатысты барлық файлдар менің қалтамнан ғана ізделетін болады. Айнымалылар жиыны бар тілдер мұрағаты LOCPATH еленбейді.

Міне, шешуші сынақ:

$> LANG=ru_MY.UTF-8 LOCPATH=~/.local/lib/locale/ sort buhg.txt
Абаканов Михаил;маляр
Ёлкина Элла;крановщица
Иванов Андрей;слесарь
Иванова Алла;адвокат

Ура! Біз бұны жасадық!

Қатемен жұмыс

Мен басында қойылған жолдарды сұрыптау туралы сұрақтарға жауап бердім, бірақ қателер туралы әлі де бірнеше сұрақтар бар - көрінетін және көрінбейтін.

Бастапқы мәселеге оралайық.

Және бағдарлама сорт және бағдарлама Қосылу сол жолды салыстыру функцияларын пайдаланыңыз glibc. Бұл қалай болды Қосылу пәрмен бойынша сұрыпталған жолдарда сұрыптау қатесін берді сорт жергілікті тілде en_US.UTF-8? Жауап қарапайым: сорт бүкіл жолды салыстырады және Қосылу әдепкі бойынша бірінші бос орын таңбасына дейінгі жолдың басы болып табылатын кілтті ғана салыстырады. Менің мысалда бұл қате туралы хабарға әкелді, себебі жолдардағы бірінші сөздердің сұрыпталуы толық жолдардың сұрыпталуына сәйкес келмеді.

Жергілікті «C» сұрыпталған жолдарда бірінші бос орынға дейінгі бастапқы ішкі жолдар да сұрыпталатынына кепілдік береді, бірақ бұл тек қатені жасырады. Қате туралы хабарсыз файлдарды біріктіру қате нәтижесін беретін деректерді (тегі бірдей, бірақ аттары әртүрлі адамдар) таңдауға болады. Қаласақ Қосылу біріктірілген файл жолдарын толық аты бойынша, содан кейін дұрыс жол өріс бөлгішті нақты көрсету және бүкіл жол бойынша емес, кілт өрісі бойынша сұрыптау болады. Бұл жағдайда біріктіру дұрыс орындалады және ешбір тілде қателер болмайды:

$> sort -t ; -k 1 buhg.txt > buhg.srt
$> sort -t ; -k 1 mail.txt > mail.srt
$> join -t ; buhg.srt mail.srt > result

Кодтаудағы сәтті орындалған мысал CP1251 басқа қатені қамтиды. Маған белгілі барлық дистрибуцияларда факт Linux пакеттерде құрастырылған тіл жоқ ru_RU.CP1251. Егер құрастырылған тіл табылмаса, онда сорт байт-байт салыстыруды үнсіз пайдаланады, бұл біз байқаған нәрсе.

Айтпақшы, құрастырылған тілдердің қол жетімсіздігіне байланысты тағы бір кішігірім ақау бар. Команда LOCPATH=/tmp тіл -a ішіндегі барлық тілдердің тізімін береді тіл мұрағаты, бірақ айнымалылар жиынымен LOCPATH барлық бағдарламалар үшін (соның ішінде көпшілігі жергілікті тіл) бұл тілдер қолжетімді болмайды.

$> LOCPATH=/tmp locale -a | grep en_US
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_COLLATE to default locale: No such file or directory
en_US
en_US.iso88591
en_US.iso885915
en_US.utf8

$> LC_COLLATE=en_US.UTF-8 sort --debug
sort: using ‘en_US.UTF-8’ sorting rules

$> LOCPATH=/tmp LC_COLLATE=en_US.UTF-8 sort --debug
sort: using simple byte comparison

қорытынды

Егер сіз жолдарды байттардың жиынтығы деп ойлауға дағдыланған бағдарламашы болсаңыз, онда сіздің таңдауыңыз LC_COLLATE=C.

Егер сіз лингвист немесе сөздік құрастырушы болсаңыз, онда сіз өз тіліңізде құрастырғаныңыз жөн.

Егер сіз қарапайым пайдаланушы болсаңыз, онда сіз жай ғана пәрменге үйренуіңіз керек ls -a әріптен басталатын файлдармен араласқан нүктеден басталатын файлдарды шығарады және Түнгі командир, ол атауларды сұрыптау үшін өзінің ішкі функцияларын қолданып, нүктеден басталатын файлдарды тізімнің басына қояды.

сілтемелер

Есеп No 10 Юникодты салыстыру алгоритмі

Unicode.org сайтындағы таңбалардың салмағы

ICU — IBM фирмасынан Юникодпен жұмыс істеуге арналған кітапхананы енгізу.

Сұрыптау сынағы ICU

Кейіпкерлердің салмағы ISO 14651

Масштабпен файл пішімін сипаттау ISO 14652

Жолды салыстыруды талқылау glibc

Ақпарат көзі: www.habr.com

пікір қалдыру