Carane Linux ngurutake strings

Pambuka

Iku kabeh diwiwiti karo script singkat sing mestine kanggo gabungke informasi alamat e-mail karyawan sing dipikolehi saka dhaptar pangguna milis, kanthi posisi karyawan sing dipikolehi saka database departemen HR. Dhaptar loro kasebut diekspor menyang file teks Unicode UTF-8 lan disimpen karo endings baris Unix.

Konten mail.txt

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

Konten buhg.txt

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

Kanggo nggabungake, file kasebut diurutake kanthi printah Unix Urut lan dikirim menyang input program Unix Gabung, sing tiba-tiba gagal karo kesalahan:

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

Deleng asil ngurutake kanthi mripat sampeyan nuduhake manawa, umume, pangurutan kasebut bener, nanging ing kasus kebetulan jeneng kulawarga lanang lan wadon, sing wadon sadurunge sing lanang:

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

Katon kaya kesalahan ngurutake ing Unicode utawa kaya manifestasi feminisme ing algoritma pangurutan. Pisanan, mesthi, luwih masuk akal.

Ayo ditundha kanggo saiki Gabung lan fokus ing Urut. Ayo dadi nyoba kanggo ngatasi masalah nggunakake poking ilmiah. Pisanan, ayo ngganti lokal saka en_US ing ru_RU. Kanggo ngurutake, cukup nyetel variabel lingkungan LC_COLLATE, nanging kita ora bakal mbuwang wektu kanggo perkara sepele:

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

Ora ana owah-owahan.

Ayo nyoba recode file dadi enkoding bait siji:

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

Maneh ora ana owah-owahan.

Ora ana sing bisa ditindakake, sampeyan kudu golek solusi ing Internet. Ora ana apa-apa langsung babagan jeneng kulawarga Rusia, nanging ana pitakonan babagan keanehan ngurutake liyane. Contone, ana masalah: unix sort nganggep karakter '-' (dash) minangka ora katon. Cekakipun, senar "a-b", "aa", "ac" diurutake minangka "aa", "a-b", "ac".

Jawaban standar ing endi wae: gunakake lokal programmer "C" lan sampeyan bakal seneng. Ayo jajal:

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

Ana sing owah. Ivanovs diantrekake ing urutan sing bener, sanajan Yolkina katon ing endi wae. Ayo bali menyang masalah asli:

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

Kerjane tanpa kesalahan, kaya sing dijanjekake Internet. Lan iki senadyan Yolkina ing baris pisanan.

Masalah kayane wis ditanggulangi, nanging yen ngono, ayo nyoba enkoding Rusia liyane - Windows CP1251:

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

Asil ngurutake, cukup aneh, bakal pas karo lokal "C", lan kabeh conto, miturut, mlaku tanpa kasalahan. Sawetara jinis mistisisme.

Aku ora seneng mistik ing program amarga biasane topeng kesalahan. Kita kudu serius ndeleng cara kerjane. Urut lan apa pengaruhe? LC_COLLATE .

Ing pungkasan aku bakal nyoba mangsuli pitakon:

  • kok jeneng wadon ora diurutake kanthi bener?
  • ngapa LANG=ru_RU.CP1251 pranyata padha karo LANG=C
  • kok gawe Urut и Gabung gagasan beda babagan urutan strings diurutake
  • kok ana kesalahan ing kabeh conto sandi?
  • pungkasane carane ngurutake senar sing dikarepake

Ngurutake ing Unicode

Stop pisanan bakal laporan technical No. 10 judhulé Algoritma pangumpulan Unicode online unicode.org. Laporan kasebut ngemot akeh rincian teknis, mula aku menehi ringkesan ringkes babagan ide utama.

collation - "mbandhingake" strings minangka basis saka algoritma ngurutake. Algoritma kasebut bisa uga beda-beda ("gelembung", "nggabung", "cepet"), nanging kabeh bakal nggunakake perbandingan sepasang senar kanggo nemtokake urutan sing katon.

Ngurutake string ing basa alam minangka masalah sing cukup rumit. Malah ing enkoding siji-byte sing paling gampang, urutan huruf ing alfabet, sanajan beda karo alfabet Latin Inggris, ora bakal pas karo urutan angka numerik sing dikodekake huruf kasebut. Dadi ing alfabet Jerman huruf kasebut Ö ngadeg antarane О и P, lan ing enkoding CP850 dheweke nemu antarane ÿ и Ü.

Sampeyan bisa nyoba abstrak saka enkoding tartamtu lan nimbang huruf "ideal" sing disusun ing sawetara urutan, kaya sing ditindakake ing Unicode. Enkoding UTF8, UTF16 utawa siji-bait KOI8-R (yen subset Unicode winates dibutuhake) bakal menehi representasi numerik huruf sing beda-beda, nanging deleng unsur sing padha ing tabel dhasar.

Pranyata metu sing malah yen kita mbangun Tabel simbol saka ngeruk, kita ora bakal bisa kanggo nemtokake urutan simbol universal. Ing macem-macem abjad nasional sing nggunakake huruf sing padha, urutan huruf kasebut bisa uga beda. Contone, ing basa Prancis Æ bakal dianggep minangka ligatur lan diurutake minangka senar AE. Ing basa Norwegia Æ bakal layang kapisah, kang dumunung sawise Z. Miturut cara, saliyane ligatures kaya Æ Ana aksara sing ditulis nganggo sawetara simbol. Dadi ing aksara Ceko ana aksara Ch, kang ngadeg antarane H и I.

Saliyane beda ing aksara, ana tradhisi nasional liyane sing mengaruhi ngurutake. Utamane, pitakonan muncul: ing urutan apa tembung sing dumadi saka huruf gedhe lan huruf cilik katon ing kamus? Ngurutake uga bisa kena pengaruh nggunakake tandha wacan. Ing basa Spanyol, tandha pitakon terbalik digunakake ing wiwitan ukara pitakon (Apa sampeyan seneng musik?). Ing kasus iki, jelas yen ukara pitakon ora kudu diklompokake dadi kluster sing kapisah ing njaba aksara, nanging kepiye carane ngurutake garis nganggo tandha wacan liyane?

Aku ora bakal mikir babagan ngurutake string ing basa sing beda banget karo basa Eropa. Elinga yen ing basa kanthi arah nulis tengen-ngiwa utawa ndhuwur-ngisor, karakter ing baris paling kamungkinan disimpen ing urutan maca, lan malah sistem nulis non-abjad duwe cara dhewe kanggo urutan baris karakter dening karakter. . Contone, hieroglif bisa diurut kanthi gaya (Tombol aksara Cina) utawa kanthi lafal. Jujur, aku ora ngerti carane emojis kudu diatur, nanging sampeyan uga bisa nggawe apa-apa.

Adhedhasar fitur sing kadhaptar ing ndhuwur, syarat dhasar kanggo mbandhingake string adhedhasar tabel Unicode dirumusake:

  • comparison strings ora gumantung ing posisi karakter ing tabel kode;
  • urutan karakter sing mbentuk karakter siji dikurangi dadi wangun kanonik (A + bunder ndhuwur padha karo Å);
  • Nalika mbandhingake senar, karakter dianggep ing konteks senar lan, yen perlu, digabungake karo tanggane dadi siji unit perbandingan (Ch ing Ceko) utawa dipérang dadi sawetara (Æ ing basa Prancis);
  • kabeh fitur nasional (abjad, huruf gedhe / cilik, tandha waca, urutan jinis nulis) kudu dikonfigurasi nganti tugas manual pesenan (emoji);
  • comparison penting ora mung kanggo ngurutake, nanging uga ing akeh panggonan liyane, contone kanggo nemtokake kisaran baris (ngganti {A... z} ing bash);
  • comparison kudu rampung cukup cepet.

Kajaba iku, panulis laporan nggawe properti perbandingan sing ora kudu diandelake dening pangembang algoritma:

  • algoritma perbandingan ngirim ora mbutuhake set karakter sing kapisah kanggo saben basa (basa Rusia lan Ukrainia nuduhake paling akeh karakter Cyrillic);
  • perbandingan ngirim ora gumantung ing urutan karakter ing tabel Unicode;
  • bobot senar ngirim ora dadi atribut saka senar, amarga senar padha ing konteks budaya beda bisa duwe bobot beda;
  • bobot baris bisa diganti nalika gabung utawa pamisah (saka x < y iku ora tindakake iku xz < yz);
  • strings beda gadhah bobot padha dianggep padha saka titik saka algoritma ngurutake. Ngenalke pesenan tambahan saka strings kuwi bisa, nanging bisa degrade kinerja;
  • Sajrone ngurutake bola-bali, baris kanthi bobot sing padha bisa diganti. Kekokohan minangka properti saka algoritma pangurutan tartamtu, lan dudu properti saka algoritma perbandingan string (pirsani paragraf sadurunge);
  • Aturan ngurutake bisa owah saka wektu nalika tradhisi budaya nyaring / diganti.

Uga ditetepake manawa algoritma perbandingan ora ngerti apa-apa babagan semantik senar sing diproses. Dadi, senar sing mung dumadi saka digit ora kudu dibandhingake karo angka, lan ing dhaptar jeneng Inggris artikel kasebut (Beatles, Ing).

Kanggo nyukupi kabeh syarat sing ditemtokake, algoritma ngurutake tabel multi-level (sajatine papat-tingkat) diusulake.

Sadurungé, karakter ing senar dikurangi dadi wangun kanonik lan diklompokaké dadi unit perbandingan. Saben unit perbandingan diwenehi sawetara bobot sing cocog karo sawetara tingkat perbandingan. Bobot saka unit mbandhingake yaiku unsur saka set sing diurutake (ing kasus iki, integer) sing bisa dibandhingake luwih utawa kurang. Makna khusus DIPOPO (0x0) tegese ing tingkat comparison cocog unit iki ora melu ing comparison. Perbandingan strings bisa diulang kaping pirang-pirang, nggunakake bobot saka tingkat sing cocog. Ing saben tingkat, bobot saka unit mbandingaken saka rong larik sing sequentially dibandhingake karo saben liyane.

Ing implementasine algoritma sing beda kanggo tradhisi nasional sing beda-beda, nilai koefisien bisa beda-beda, nanging standar Unicode kalebu tabel bobot dhasar - "Tabel Elemen Koleksi Unicode Default" (DUCET). Aku pengin Wigati sing nyetel variabel LC_COLLATE bener pratondo saka pilihan saka Tabel bobot ing fungsi comparison senar.

Koefisien bobot DUCET diatur kaya ing ngisor iki:

  • ing tingkat pisanan, kabeh huruf dikurangi dadi kasus sing padha, diakritik dibuwang, tandha wacan (ora kabeh) ora digatekake;
  • ing tingkat kapindho, mung diakritik sing dianggep;
  • ing tingkat katelu, mung kasus sing dianggep;
  • ing tataran kaping papat, mung tandha wacan sing digatekake.

Perbandingan kasebut dumadi ing sawetara pass: pisanan, koefisien tingkat pertama dibandhingake; yen bobote pas, banjur mbandhingake maneh karo bobot tingkat kapindho ditindakake; banjur mbok menawa katelu lan papat.

Perbandingan rampung nalika larik ngemot unit perbandingan sing cocog karo bobot sing beda. Baris sing bobote padha ing kabeh papat tingkat dianggep padha karo siji liyane.

Algoritma iki (kanthi akeh rincian teknis tambahan) menehi jeneng kanggo laporan No. 10 - "Algoritma Pengumpulan Unicode" (ACU).

Iki ngendi prilaku ngurutake saka conto kita dadi sethitik luwih cetha. Luwih becik mbandhingake karo standar Unicode.

Kanggo nguji implementasine ACU ana khusus tes, nggunakake file bobot, ngleksanakake DUCET. Sampeyan bisa nemokake kabeh jinis lucu ing file timbangan. Contone, ana urutan mahjong lan domino Eropa, uga urutan jas ing dek kertu (simbol 1F000 lan luwih). Setelan kertu diselehake miturut aturan jembatan - PCBT, lan kertu ing setelan kasebut ana ing urutan T, 2,3, XNUMX... K.

Priksa kanthi manual manawa baris diurutake kanthi bener miturut DUCET bakal cukup mboseni, nanging untunge kanggo kita, ana eksekusi perpustakaan teladan kanggo nggarap Unicode - "Komponen Internasional kanggo Unicode"(ICU).

Ing situs web perpustakaan iki, dikembangake ing IBM, ana kaca demo, kalebu kaca algoritma comparison string. We ngetik garis test kita karo setelan gawan lan, lah, kita njaluk ngurutake Russian sampurna.

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

Miturut cara, situs web ICU Sampeyan bisa nemokake klarifikasi algoritma perbandingan nalika ngolah tandha wacan. Ing conto Koleksi FAQ apostrof lan hyphen ora digatekake.

Unicode mbantu kita, nanging goleki alasan kanggo prilaku aneh Urut в Linux kudu lunga menyang papan liya.

Ngurutake ing glibc

Tampilan cepet kode sumber utilitas Urut saka GNU Core Utils nuduhake yen ing sarana kasebut, lokalisasi mudhun kanggo nyithak nilai variabel saiki LC_COLLATE nalika mlaku ing mode debug:

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

Perbandingan string ditindakake kanthi nggunakake fungsi standar strcoll, sing tegese kabeh menarik ana ing perpustakaan glibc.

Ing wiki saka project glibc darmabakti kanggo comparison senar siji paragraf. Saking paragraf menika saged dipunmangertosi bilih ing glibc ngurutake adhedhasar algoritma sing wis kita kenal ACU (Algoritma pangumpulan Unicode) lan / utawa ing standar sing cedhak ISO 14651 (Urutan string internasional lan perbandingan). Babagan standar paling anyar, kudu dicathet yen ing situs kasebut standards.iso.org ISO 14651 resmi ngumumake kasedhiya kanggo umum, nanging pranala sing cocog ndadékaké menyang kaca sing ora ana. Google ngasilake sawetara kaca kanthi pranala menyang situs resmi sing nawakake tuku salinan elektronik standar kanthi rega satus euro, nanging ing kaca katelu utawa kaping papat asil panelusuran uga ana pranala langsung menyang PDF. Umumé, standar kasebut meh ora beda karo ACU, nanging luwih mboseni diwaca amarga ora ngemot conto sing jelas babagan fitur nasional ngurutake senar.

Informasi paling menarik ing wiki ana link menyang bug tracker karo rembugan saka implementasine saka comparison senar ing glibc. Saka pirembagan kasebut bisa diweruhi glibc digunakake kanggo mbandhingake senar ISOmeja pribadi Tabel Cithakan Umum (CTT), alamat sing bisa ditemokake ing aplikasi kasebut A standar ISO 14651. Antarane 2000 lan 2015 tabel iki ing glibc ora duwe maintainer lan cukup beda (paling externally) saka versi saiki standar. Saka 2015 nganti 2018, adaptasi menyang versi tabel anyar ditindakake, lan saiki sampeyan duwe kesempatan kanggo ketemu ing urip nyata versi tabel anyar (CentOS 8), lan lawas (CentOS 7).

Saiki kita duwe kabeh informasi babagan algoritma lan tabel tambahan, kita bisa bali menyang masalah asli lan ngerti carane ngurutake strings ing lokal Russian.

ISO 14651 / 14652

Kode sumber tabel kita kasengsem ing CTT ing paling distribusi Linux ana ing katalog /usr/share/i18n/locales/. Tabel kasebut dhewe ana ing file kasebut iso14651_t1_common. Banjur iki arahan file copy iso14651_t1_common kalebu ing file iso14651_t1, kang, ing siji, kalebu ing file nasional, kalebu en_US и ru_RU. Ing paling distribusi Linux kabeh file sumber kalebu ing instalasi dhasar, nanging yen padha ora ana, sampeyan kudu nginstal paket tambahan saka distribusi.

Struktur berkas iso14651_t1 bisa uga katon banget verbose, karo aturan non-jelas kanggo mbangun jeneng, nanging yen katon ing, kabeh iku cukup prasaja. Struktur kasebut diterangake ing standar ISO 14652, salinan sing bisa diundhuh saka situs web open-std.org. Katrangan liyane babagan format file bisa diwaca ing spesifikasi POSIX saka OpenGroup. Minangka alternatif kanggo maca standar, sampeyan bisa sinau kode sumber fungsi collate_maca в glibc/locale/programs/ld-collate.c.

Struktur file katon kaya iki:

Kanthi gawan, karakter digunakake minangka karakter uwal, lan mburi baris sawise karakter # minangka komentar. Kaloro simbol kasebut bisa didefinisikan maneh, yaiku apa sing ditindakake ing tabel versi anyar:

escape_char /
comment_char %

File kasebut bakal ngemot token ing format kasebut utawa (Endi x - digit heksadesimal). Iki minangka perwakilan heksadesimal saka titik kode Unicode ing enkoding UCS-4 (UTF-32). Kabeh unsur liyane ing kurung sudut (kalebu , <2> lan liya-liyane) dianggep minangka konstanta senar sing prasaja sing ora nduweni arti ing njaba konteks.

Senar LC_COLLATE ngandhani kita sing sabanjuré wiwit data njlentrehke comparison saka strings.

Pisanan, jeneng ditemtokake kanggo bobot ing tabel perbandingan lan jeneng kanggo kombinasi simbol. Umumé, rong jinis jeneng kasebut kalebu rong entitas sing beda-beda, nanging ing file asline dicampur. Jeneng bobot kasebut ditemtokake dening tembung kunci collating-simbol (karakter mbandhingake) amarga nalika mbandhingake, karakter Unicode sing bobote padha bakal dianggep minangka karakter sing padha.

Dawane total bagean ing revisi file saiki kira-kira 900 baris. Aku narik conto saka sawetara panggonan kanggo nuduhake arbitrariness jeneng lan sawetara jinis sintaksis.

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>"

  • collating-symbol log string OSMANYA ing tabel jeneng timbangan
  • simbol-collating .. ndhaftar urutan jeneng sing dumadi saka ater-ater S lan sufiks angka heksadesimal saka 1D000 kanggo 1D35F.
  • Ffff в collating-simbol katon kaya integer unsigned gedhe ing heksadesimal, nanging iku mung jeneng sing bisa katon kaya
  • Deleng tegese titik kode ing encoding UCS-4
  • nglumpukake-elemen saka "" ndhaptar jeneng anyar kanggo pasangan titik Unicode.

Sawise jeneng bobot ditetepake, bobot sing nyata ditemtokake. Amarga mung hubungan sing luwih gedhe tinimbang sing luwih cilik tinimbang dibandhingake, bobote ditemtokake kanthi urutan jeneng dhaptar sing prasaja. Bobot "luwih entheng" kadhaptar dhisik, banjur bobot "luwih abot". Ayo kula ngelingake yen saben karakter Unicode diwenehi papat bobot sing beda. Ing kene padha digabung dadi siji urutan urutan. Ing teori, jeneng simbolis bisa digunakake ing salah siji saka papat tingkat, nanging komentar nuduhake yen pangembang mental misahake jeneng dadi tingkat.

% 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

Pungkasan, tabel bobot nyata.

Bagean bobot wis dilampirake ing baris tembung kunci pesen_wiwitan и pesenan_pungkasan. Pilihan ekstra pesen_wiwitan nemtokake arah baris sing dipindai ing saben tingkat perbandingan. Setelan gawan yaiku maju. Awak bagean kasebut dumadi saka garis sing ngemot kode simbol lan bobot papat. Kode karakter bisa diwakili dening karakter kasebut dhewe, titik kode, utawa jeneng simbolis sing wis ditemtokake sadurunge. Bobot uga bisa diwenehi jeneng simbolis, titik kode, utawa simbol kasebut dhewe. Yen titik kode utawa karakter digunakake, bobote padha karo nilai numerik titik kode (posisi ing tabel Unicode). Karakter sing ora ditemtokake sacara eksplisit (aku ngerti) dianggep ditugasake ing meja kanthi bobot utama sing cocog karo posisi ing tabel Unicode. Nilai bobot khusus TANPA NGANGGO tegese simbol digatèkaké ing tingkat cocok saka comparison.

Kanggo nduduhake struktur timbangan, aku milih telung fragmen sing cukup jelas:

  • karakter sing rampung digatèkaké
  • simbol padha karo nomer telu ing rong tingkat pisanan
  • wiwitan aksara Sirilik, kang ora ngemot diacritics, lan mulane diurutake utamané dening tingkat pisanan lan katelu.

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

Saiki sampeyan bisa bali ngurutake conto saka wiwitan artikel. Ambush dumunung ing bagean iki saka tabel bobot:

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

Bisa dideleng yen ing tabel iki tandha wacan saka tabel ASCII (kalebu spasi) meh tansah digatèkaké nalika mbandhingaké strings. Pangecualian mung garis sing cocog ing kabeh kajaba tandha wacan sing ditemokake ing posisi sing cocog. Garis saka conto (sawise ngurutake) kanggo algoritma perbandingan katon kaya iki:

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

Menimbang yen ing tabel timbangan, huruf kapital ing Rusia teka sawise huruf cilik (ing tingkat katelu luwih abot tinimbang ), pangurutan katon pancen bener.

Nalika nyetel variabel LC_COLLATE=C tabel khusus dimuat sing nemtokake comparison byte-by-byte

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'
};

Wiwit ing Unicode titik kode Ё teka sadurunge A, strings diurutake miturut.

Tabel teks lan binar

Temenan, perbandingan string minangka operasi sing umum banget, lan parsing tabel CTT prosedur sing cukup larang. Kanggo ngoptimalake akses menyang tabel, dikompilasi menyang wangun binar kanthi printah localdef.

tim localdef nampa minangka parameter file kanthi tabel karakteristik nasional (opsi -i), ing ngendi kabeh karakter diwakili dening titik Unicode, lan file korespondensi antarane titik Unicode lan karakter saka enkoding tartamtu (opsi). -f). Minangka asil karya, file binar digawe kanggo lokal kanthi jeneng sing ditemtokake ing parameter pungkasan.

glibc ndhukung rong format file binar: "tradisional" lan "modern".

Format tradisional tegese jeneng lokal yaiku jeneng subdirektori ing /usr/lib/lokal/. Subdirektori iki nyimpen file binar LC_COLLATE, LC_CTYPE, LC_TIME lan liya-liyane. File LC_IDENTIFICATION ngemot jeneng resmi lokal (sing bisa uga beda karo jeneng direktori) lan komentar.

Format modern kalebu nyimpen kabeh lokal ing siji arsip /usr/lib/locale/locale-archive, kang wis dipetakan menyang memori virtual kabeh pangolahan nggunakake glibc. Jeneng lokal ing format modern tundhuk sawetara kanonisasi - mung angka lan huruf cilik sing tetep ana ing jeneng enkoding. Dadi ru_RU.KOI8-R, bakal disimpen minangka ru_RU.koi8r.

File input ditelusuri ing direktori saiki, uga ing direktori /usr/share/i18n/locales/ и /usr/share/i18n/charmaps/ kanggo file CTT lan file enkoding, mungguh.

Contone, printah

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

bakal ngumpulake file /usr/share/i18n/locales/ru_RU nggunakake file encoding /usr/share/i18n/charmaps/MAC-CYRILLIC.gz lan nyimpen asil ing /usr/lib/locale/locale-archive miturut jeneng ru_RU.maccyrillic

Yen sampeyan nyetel variabel LANG = en_US.UTF-8 sing glibc bakal nggoleki binari lokal ing urutan file lan direktori ing ngisor iki:

/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/

Yen lokal ana ing format tradisional lan modern, banjur prioritas diwenehi kanggo sing modern.

Sampeyan bisa ndeleng dhaptar lokal sing dikompilasi nganggo perintah kasebut lokal-a.

Nyiyapake tabel perbandingan sampeyan

Saiki, bersenjata karo kawruh, sampeyan bisa nggawe tabel comparison string becik dhewe. Tabel iki kudu mbandhingake huruf Rusia kanthi bener, kalebu huruf Ё, lan ing wektu sing padha njupuk tandha wacan sing cocog karo tabel. ASCII.

Proses nyiapake tabel ngurutake dhewe dumadi saka rong tahapan: nyunting tabel bobot lan nyusun dadi bentuk binar kanthi printah. localdef.

Supaya tabel perbandingan bisa diatur kanthi biaya panyuntingan minimal, ing format kasebut ISO 14652 Bagean kanggo nyetel bobot saka tabel sing ana kasedhiya. Bagian kasebut diwiwiti kanthi tembung kunci reorder-sawise lan nuduhake posisi sawise panggantos ditindakake. Bagean rampung karo baris reorder-mburi. Yen perlu kanggo mbenerake sawetara bagean saka tabel, banjur bagean digawe kanggo saben bagean kuwi.

Aku nyalin versi anyar saka file iso14651_t1_common и ru_RU saka gudang glibc menyang direktori omahku ~/.local/share/i18n/locales/ lan rada nyunting bagean kasebut LC_COLLATE в ru_RU. Versi file anyar kompatibel karo versiku glibc. Yen sampeyan pengin nggunakake versi file lawas, sampeyan kudu ngganti jeneng simbolis lan panggonan ing ngendi panggantos diwiwiti ing meja.

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

Ing kasunyatan, iku bakal perlu kanggo ngganti kothak ing LC_IDENTIFICATION supaya padha nunjuk menyang lokal ru_MY, nanging ing conto iki ora dibutuhake, amarga aku ora kalebu arsip saka panelusuran lokal arsip lokal.

sing localdef nggarap file ing folderku liwat variabel I18NPATH Sampeyan bisa nambah direktori tambahan kanggo nggoleki file input, lan direktori kanggo nyimpen file binar bisa ditemtokake minangka jalur kanthi garis miring:

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

POSIX nganggep yen ing BASA sampeyan bisa nulis path absolut kanggo direktori karo file lokal, miwiti karo garis miring maju, nanging glibc в Linux kabeh path diitung saka direktori dhasar, sing bisa ditindhes liwat variabel LOCPATH. Sawise instalasi LOCPATH=~/.local/lib/locale/ kabeh file sing ana gandhengane karo lokalisasi bakal digoleki mung ing folderku. Arsip lokal kanthi set variabel LOCPATH digatekake.

Mangkene tes sing nemtokake:

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

Hore! Kita nindakaken!

Bug kerja

Aku wis mangsuli pitakonan babagan ngurutake senar ing wiwitan, nanging isih ana sawetara pitakonan babagan kesalahan - katon lan ora katon.

Ayo bali menyang masalah asli.

Lan program Urut lan program kasebut Gabung nggunakake fungsi comparison senar padha saka glibc. Kepiye kedadeyan kasebut Gabung menehi kesalahan ngurutake ing baris diurutake dening printah Urut ing lokal en_US.UTF-8? Jawaban iki prasaja: Urut mbandhingaké kabeh senar, lan Gabung mbandhingaké mung tombol, kang minangka standar wiwitan senar nganti karakter whitespace pisanan. Ing contoku, iki nyebabake pesen kesalahan amarga ngurutake tembung pisanan ing baris ora cocog karo ngurutake baris lengkap.

lokal "C" njamin yen ing strings diurutake substrings dhisikan nganti spasi pisanan uga bakal diurutake, nanging iki mung nutupi kesalahan. Sampeyan bisa milih data (wong kanthi jeneng sing padha, nanging beda jeneng) sing, tanpa pesen kesalahan, bakal menehi asil gabungan file sing salah. Yen kita pengin Gabung gabungan baris file kanthi jeneng lengkap, banjur cara sing bener yaiku kanthi jelas nemtokake pemisah lapangan lan urut miturut kolom kunci, lan dudu kabeh baris. Ing kasus iki, gabungan bakal diterusake kanthi bener lan ora bakal ana kesalahan ing sembarang lokal:

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

Kasil dieksekusi conto ing encoding CP1251 ngandhut kesalahan liyane. Kasunyatan iku ing kabeh distribusi dikenal kanggo kula Linux paket ilang lokal dikompilasi ru_RU.CP1251. Yen lokal sing dikompilasi ora ditemokake, banjur Urut meneng nggunakake comparison byte-by-byte, kang kita diamati.

Miturut cara, ana kesalahan cilik liyane sing ana gandhengane karo ora bisa diakses lokal sing dikompilasi. tim LOCPATH=/tmp lokal -a bakal menehi dhaptar kabeh lokal ing arsip lokal, nanging karo set variabel LOCPATH kanggo kabeh program (kalebu paling akeh lokal) lokal iki ora bakal kasedhiya.

$> 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

kesimpulan

Yen sampeyan programmer sing digunakake kanggo mikir sing strings pesawat saka bita, banjur pilihan LC_COLLATE=C.

Yen sampeyan ahli basa utawa kompiler kamus, luwih becik sampeyan ngumpulake ing lokal sampeyan.

Yen sampeyan pangguna prasaja, sampeyan mung kudu njaluk digunakake kanggo kasunyatan sing printah ls -a file output miwiti karo titik pipis karo file miwiti karo huruf, lan Komandan tengah wengi, sing nggunakake fungsi internal dhewe kanggo ngurutake jeneng, sijine file sing diwiwiti kanthi titik ing wiwitan dhaptar.

referensi

Algoritma pangumpulan Unicode Nomer 10 Laporan

Bobot karakter ing unicode.org

ICU - implementasi perpustakaan kanggo nggarap Unicode saka IBM.

Tes ngurutake nggunakake ICU

Bobot karakter ing ISO 14651

Katrangan babagan format file kanthi timbangan ISO 14652

Diskusi perbandingan string ing glibc

Source: www.habr.com

Add a comment