Ինչպես է Linux-ի տեսակավորումը դասավորում տողերը

Ներածություն

Ամեն ինչ սկսվեց կարճ սցենարից, որը պետք է միավորեր հասցեի տեղեկատվությունը e-mail փոստի ցուցակից օգտվողների ցուցակից ստացված աշխատակիցները, կադրերի բաժնի տվյալների բազայից ստացված աշխատակիցների պաշտոնները: Երկու ցուցակներն էլ արտահանվել են Յունիկոդ տեքստային ֆայլեր 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
Абаканов Михаил;маляр
Ёлкина Элла;крановщица
Иванова Алла;маляр
Иванов Андрей;слесарь

Կարծես Unicode-ում տեսակավորման անսարքություն է կամ տեսակավորման ալգորիթմում ֆեմինիզմի դրսևորում: Առաջինն, իհարկե, ավելի հավանական է։

Առայժմ հետաձգենք միանալ և կենտրոնանալ տեսակ. Փորձենք խնդիրը լուծել՝ օգտագործելով գիտական ​​պոկելը։ Նախ, եկեք փոխենք տեղանքը 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 տեսակավորումը վերաբերվում է «-» (գծիկ) նիշերին որպես անտեսանելի. Մի խոսքով, «a-b», «aa», «ac» տողերը դասավորված են «aa», «a-b», «ac»:

Պատասխանն ամենուր ստանդարտ է. օգտագործեք ծրագրավորողի տեղայնությունը «Գ» և դու երջանիկ կլինես: Արի փորձենք:

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

Տեսակավորման արդյունքը, տարօրինակ կերպով, կհամընկնի տեղանքի հետ «Գ», և ամբողջ օրինակը, համապատասխանաբար, աշխատում է առանց սխալների: Ինչ-որ միստիցիզմ.

Ես չեմ սիրում միստիկան ծրագրավորման մեջ, քանի որ այն սովորաբար քողարկում է սխալները: Մենք պետք է լրջորեն նայենք, թե ինչպես է այն աշխատում: տեսակ և ինչի՞ վրա է դա ազդում LC_COLLATE .

Վերջում ես կփորձեմ պատասխանել հարցերին.

  • ինչո՞ւ են իգական սեռի ազգանունները սխալ դասավորված:
  • ինչու LANG=ru_RU.CP1251 պարզվեց, որ համարժեք է LANG=C
  • ինչու անել տեսակ и միանալ տարբեր պատկերացումներ տեսակավորված տողերի հերթականության մասին
  • ինչու՞ կան սխալներ իմ բոլոր օրինակներում:
  • վերջապես ինչպես դասավորել տողերը ըստ ձեր ցանկության

Տեսակավորում Unicode-ում

Առաջին կանգառը կլինի թիվ 10 տեխնիկական հաշվետվությունը՝ վերնագրով Յունիկոդի համադրման ալգորիթմ առցանց unicode.org. Զեկույցը պարունակում է շատ տեխնիկական մանրամասներ, ուստի թույլ տվեք հակիրճ ամփոփել հիմնական գաղափարները:

Համեմատում — տողերի «համեմատումը» ցանկացած տեսակավորման ալգորիթմի հիմքն է։ Ալգորիթմներն իրենք կարող են տարբերվել («փուչիկ», «միաձուլվել», «արագ»), բայց դրանք բոլորը կօգտագործեն զույգ տողերի համեմատությունը՝ որոշելու դրանց հայտնվելու հերթականությունը:

Բնական լեզվով տողերի տեսակավորումը բավականին բարդ խնդիր է: Նույնիսկ ամենապարզ մեկ բայթ կոդավորումներում, այբուբենի տառերի կարգը, նույնիսկ ինչ-որ կերպ տարբերվում է անգլիական լատինական այբուբենից, այլևս չի համընկնի թվային արժեքների կարգի հետ, որոնցով կոդավորված են այս տառերը: Այսպիսով, գերմանական այբուբենում տառը Ö միջեւ կանգնած է О и P, և կոդավորման մեջ CP850 նա ընկնում է միջև ÿ и Ü.

Դուք կարող եք փորձել վերացական լինել կոնկրետ կոդավորումից և դիտարկել «իդեալական» տառերը, որոնք դասավորված են որոշակի հերթականությամբ, ինչպես դա արվում է Յունիկոդում: Կոդավորումներ UTF8, UTF16 կամ մեկ բայթ KOI8-R (եթե Unicode-ի սահմանափակ ենթաբազմություն է անհրաժեշտ) կտա տառերի տարբեր թվային ներկայացումներ, բայց վերաբերում է բազային աղյուսակի նույն տարրերին:

Ստացվում է, որ եթե նույնիսկ զրոյից խորհրդանիշների աղյուսակ կառուցենք, չենք կարողանա դրան համընդհանուր սիմվոլային կարգ նշանակել։ Տարբեր ազգային այբուբեններում, որոնք օգտագործում են նույն տառերը, այս տառերի հերթականությունը կարող է տարբերվել: Օրինակ՝ ֆրանսերեն Æ կհամարվի կապանք և կտեսակավորվի որպես լար AE. Նորվեգերեն Æ կլինի առանձին նամակ, որը գտնվում է հետո Z. Ի դեպ, ի լրումն ligatures նման Æ Կան մի քանի նշաններով գրված տառեր։ Այսպիսով, չեխական այբուբենում տառ կա Ch, որը կանգնած է միջեւ H и I.

Բացի այբուբենների տարբերություններից, կան այլ ազգային ավանդույթներ, որոնք ազդում են տեսակավորման վրա: Մասնավորապես, հարց է առաջանում՝ մեծ և փոքրատառերից բաղկացած բառերը ի՞նչ հերթականությամբ պետք է հայտնվեն բառարանում։ Տեսակավորման վրա կարող է ազդել նաև կետադրական նշանների օգտագործումը: Իսպաներենում շրջված հարցական նշանն օգտագործվում է հարցական նախադասության սկզբում (Ձեզ դուր է գալիս երաժշտությունը:) Այս դեպքում ակնհայտ է, որ հարցական նախադասությունները չպետք է խմբավորվեն առանձին կլաստերի մեջ այբուբենից դուրս, բայց ինչպե՞ս դասավորել տողերը այլ կետադրական նշաններով։

Ես չեմ անդրադառնա եվրոպականից շատ տարբեր լեզուներով տողերի տեսակավորմանը: Նկատի ունեցեք, որ աջից ձախ կամ վերևից ներքև գրելու ուղղություն ունեցող լեզուներում տողերի նիշերը, ամենայն հավանականությամբ, պահվում են ընթերցման կարգով, և նույնիսկ ոչ այբբենական գրելու համակարգերն ունեն տողերը նիշ առ նիշ դասավորելու իրենց ձևերը: . Օրինակ, հիերոգլիֆները կարելի է պատվիրել ըստ ոճի (Չինական նիշերի բանալիներ) կամ արտասանությամբ։ Անկեղծ ասած, ես պատկերացում չունեմ, թե ինչպես պետք է դասավորել էմոջիները, բայց դուք նույնպես կարող եք ինչ-որ բան հորինել նրանց համար:

Ելնելով վերը թվարկված հատկանիշներից՝ ձևակերպվել են Unicode աղյուսակների վրա հիմնված տողերի համեմատման հիմնական պահանջները.

  • տողերի համեմատությունը կախված չէ կոդերի աղյուսակում նիշերի դիրքից.
  • մեկ նիշ ձևավորող նիշերի հաջորդականությունը վերածվում է կանոնական ձևի (A + վերին շրջանը նույնն է, ինչ Å);
  • Տողերը համեմատելիս նիշը դիտարկվում է տողի համատեքստում և, անհրաժեշտության դեպքում, համակցվում իր հարևանների հետ համեմատության մեկ միավորի մեջ (Ch չեխերեն) կամ բաժանված է մի քանիսի (Æ Ֆրանսերեն);
  • բոլոր ազգային հատկանիշները (այբուբեն, մեծատառ/փոքրատառ, կետադրական նշան, գրելու տեսակների հերթականություն) պետք է կազմաձևվեն մինչև պատվերի ձեռքով նշանակման (էմոջի)
  • համեմատությունը կարևոր է ոչ միայն տեսակավորման համար, այլ նաև շատ այլ վայրերում, օրինակ՝ տողերի միջակայքերը նշելու համար (փոխարինելով {A... z}-ը): ուժեղ հարվածել);
  • համեմատությունը պետք է կատարվի բավականին արագ:

Բացի այդ, զեկույցի հեղինակները ձևակերպել են համեմատական ​​հատկություններ, որոնց վրա ալգորիթմ մշակողները չպետք է ապավինեն.

  • Համեմատության ալգորիթմը չպետք է պահանջի նիշերի առանձին շարք յուրաքանչյուր լեզվի համար (ռուսերեն և ուկրաիներեն լեզուները կիսում են կիրիլյան նիշերի մեծ մասը);
  • համեմատությունը չպետք է հիմնվի Յունիկոդ աղյուսակների նիշերի հերթականության վրա.
  • լարային կշիռը չպետք է լինի լարային հատկանիշ, քանի որ նույն տողը տարբեր մշակութային համատեքստերում կարող է ունենալ տարբեր կշիռներ.
  • Շարքի կշիռները կարող են փոխվել միաձուլման կամ բաժանման ժամանակ (սկսած x < y դրանից չի բխում xz < yz);
  • Նույն կշիռ ունեցող տարբեր տողերը դասակարգման ալգորիթմի տեսանկյունից համարվում են հավասար: Նման լարերի լրացուցիչ դասավորության ներմուծումը հնարավոր է, բայց դա կարող է վատթարացնել կատարումը.
  • Կրկնվող տեսակավորման ժամանակ նույն կշիռներով տողերը կարող են փոխանակվել: Կայունությունը տեսակավորման հատուկ ալգորիթմի հատկություն է, և ոչ թե տողերի համեմատության ալգորիթմի հատկություն (տե՛ս նախորդ պարբերությունը);
  • Տեսակավորման կանոնները կարող են փոխվել ժամանակի ընթացքում, քանի որ մշակութային ավանդույթները կատարելագործվում են/փոխվում:

Նաև ամրագրված է, որ համեմատության ալգորիթմը ոչինչ չգիտի մշակվող տողերի իմաստաբանության մասին։ Այսպիսով, միայն թվանշաններից բաղկացած տողերը չպետք է համեմատվեն որպես թվեր, իսկ անգլերեն անունների ցուցակներում հոդվածը (Beatles, The).

Այս բոլոր պահանջները բավարարելու համար առաջարկվում է բազմաստիճան (իրականում չորս մակարդակ) աղյուսակների տեսակավորման ալգորիթմ:

Նախկինում տողի նիշերը վերածվել են կանոնական ձևի և խմբավորվել համեմատության միավորների մեջ։ Համեմատության յուրաքանչյուր միավորին վերագրվում են մի քանի կշիռներ, որոնք համապատասխանում են համեմատության մի քանի մակարդակներին: Համեմատության միավորների կշիռները դասավորված բազմությունների (այս դեպքում՝ ամբողջ թվերի) տարրերն են, որոնք կարելի է համեմատել քիչ թե շատ։ Հատուկ նշանակություն ԱՆՏԵՍՎԱԾ (0x0) նշանակում է, որ համապատասխան համեմատության մակարդակում այս միավորը ներգրավված չէ համեմատության մեջ: Լարերի համեմատությունը կարելի է մի քանի անգամ կրկնել՝ օգտագործելով համապատասխան մակարդակների կշիռները։ Յուրաքանչյուր մակարդակում երկու տողերի համեմատական ​​միավորների կշիռները հաջորդաբար համեմատվում են միմյանց հետ:

Տարբեր ազգային ավանդույթների համար ալգորիթմի տարբեր իրականացումներում գործակիցների արժեքները կարող են տարբերվել, բայց Յունիկոդ ստանդարտը ներառում է կշիռների հիմնական աղյուսակը. «Լռելյայն Յունիկոդի հավաքման տարրերի աղյուսակ» (DUCET) Ցանկանում եմ նշել, որ փոփոխականի կարգավորումը LC_COLLATE իրականում տողերի համեմատության ֆունկցիայի քաշի աղյուսակի ընտրության ցուցանիշ է:

Կշռման գործակիցներ DUCET դասավորված է հետևյալ կերպ.

  • առաջին մակարդակում բոլոր տառերը կրճատվում են նույն գործով, դիակրիտիկները հանվում են, կետադրական նշանները (ոչ բոլորը) անտեսվում են.
  • երկրորդ մակարդակում հաշվի են առնվում միայն դիակրիտիկները.
  • երրորդ մակարդակում հաշվի է առնվում միայն դեպքը.
  • չորրորդ մակարդակում հաշվի են առնվում միայն կետադրական նշանները։

Համեմատությունը տեղի է ունենում մի քանի անցումներով. նախ համեմատվում են առաջին մակարդակի գործակիցները. եթե կշիռները համընկնում են, ապա կրկնակի համեմատություն է կատարվում երկրորդ մակարդակի կշիռների հետ. հետո գուցե երրորդն ու չորրորդը:

Համեմատությունն ավարտվում է, երբ տողերը պարունակում են տարբեր կշիռների հետ համեմատության համապատասխան միավորներ: Բոլոր չորս մակարդակներում հավասար կշիռ ունեցող տողերը համարվում են միմյանց հավասար:

Այս ալգորիթմը (մի փունջ լրացուցիչ տեխնիկական մանրամասներով) տվել է թիվ 10 զեկույցի անունը. «Յունիկոդի հավաքման ալգորիթմ» (ACU).

Այստեղ է, որ մեր օրինակի տեսակավորման պահվածքը մի փոքր ավելի պարզ է դառնում: Լավ կլիներ այն համեմատել Յունիկոդ ստանդարտի հետ։

Իրականացումները փորձարկելու համար ACU կա հատուկ փորձարկում, օգտագործելով կշիռների ֆայլը, իրականացնելով DUCET. Կշեռքի ֆայլում կարող եք գտնել բոլոր տեսակի զվարճալի բաներ: Օրինակ, կա մահջոնգի և եվրոպական դոմինոյի կարգը, ինչպես նաև քարտերի տախտակամածի կոստյումների կարգը (խորհրդանիշ. 1F000 և հետագա): Քարտային կոստյումները տեղադրվում են ըստ կամրջի կանոնների՝ PCBT, իսկ կոստյումի քարտերը՝ T, 2,3, XNUMX... Կ.

Ձեռքով ստուգելով, որ տողերը ճիշտ են դասավորված ըստ DUCET բավականին հոգնեցուցիչ կլիներ, բայց, բարեբախտաբար մեզ համար, կա գրադարանի օրինակելի ներդրում Unicode-ի հետ աշխատելու համար.Միջազգային բաղադրիչներ Unicode-ի համար»(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.

On Վիքիփեդիա, ազատ հանրագիտարան ծրագրի նախագիծը glibc նվիրված տողերի համեմատությանը մեկ պարբերություն. Այս պարբերությունից կարելի է հասկանալ, որ ներս glibc տեսակավորումը հիմնված է մեզ արդեն հայտնի ալգորիթմի վրա ACU (Յունիկոդի համադրման ալգորիթմ) և/կամ դրան մոտ ստանդարտով ISO 14651 (Լարերի միջազգային պատվիրում և համեմատություն) Ինչ վերաբերում է վերջին ստանդարտին, ապա պետք է նշել, որ կայքում standards.iso.org ISO 14651 պաշտոնապես հայտարարված է հանրությանը հասանելի, սակայն համապատասխան հղումը տանում է դեպի գոյություն չունեցող էջ։ Google-ը վերադարձնում է մի քանի էջ՝ հղումներով դեպի պաշտոնական կայքեր, որոնք առաջարկում են գնել ստանդարտի էլեկտրոնային պատճենը հարյուր եվրոյով, սակայն որոնման արդյունքների երրորդ կամ չորրորդ էջում կան նաև ուղիղ հղումներ դեպի PDF. Ընդհանուր առմամբ, ստանդարտը գործնականում չի տարբերվում ACU, բայց ավելի ձանձրալի է կարդալը, քանի որ այն չի պարունակում լարային տեսակավորման ազգային առանձնահատկությունների հստակ օրինակներ։

Ամենահետաքրքիր տեղեկատվությունը Վիքիփեդիա, ազատ հանրագիտարան հղում կար bug tracker մեջ տողերի համեմատության իրականացման քննարկումով 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. Որպես ստանդարտ կարդալու այլընտրանք, կարող եք ուսումնասիրել ֆունկցիայի սկզբնական կոդը collate_read в glibc/locale/programs/ld-collate.c.

Ֆայլի կառուցվածքը հետևյալն է.

Լռելյայնորեն, նիշը օգտագործվում է որպես փախուստի նշան, իսկ # նիշից հետո տողի վերջը մեկնաբանություն է: Երկու խորհրդանիշները կարող են վերասահմանվել, ինչն արվում է աղյուսակի նոր տարբերակում.

escape_char /
comment_char %

Ֆայլը կպարունակի նշաններ ձևաչափով կամ (որտեղ x - տասնվեցական թվանշան): Սա կոդավորման մեջ Unicode ծածկագրի կետերի տասնվեցական պատկերն է UCS-4 (UTF-32) Բոլոր մյուս տարրերը անկյունային փակագծերում (ներառյալ , <2> և այլն) համարվում են պարզ տողային հաստատուններ, որոնք համատեքստից դուրս քիչ նշանակություն ունեն:

Լարային 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 и պատվեր_վերջ. Լրացուցիչ ընտրանքներ order_start որոշել, թե որ ուղղությամբ են տողերը սկանավորվում համեմատության յուրաքանչյուր մակարդակում: Լռելյայն կարգավորումն է առաջ. Բաժնի մարմինը բաղկացած է տողերից, որոնք պարունակում են խորհրդանիշի կոդը և դրա չորս կշիռները: Նիշերի կոդը կարող է ներկայացվել հենց նիշով, ծածկագրի կետով կամ նախկինում սահմանված խորհրդանշական անունով: Կշիռները կարող են տրվել նաև խորհրդանշական անուններին, ծածկագրային կետերին կամ հենց խորհրդանիշներին: Եթե ​​օգտագործվում են ծածկագրի կետերը կամ նիշերը, ապա դրանց քաշը նույնն է, ինչ կոդային կետի թվային արժեքը (դիրքը Յունիկոդ աղյուսակում): Հստակորեն չնշված (ինչպես ես հասկացա) նիշերը համարվում են աղյուսակին վերագրված առաջնային կշիռով, որը համապատասխանում է Յունիկոդ աղյուսակի դիրքին: Հատուկ քաշի արժեք ԻԳՆՈՐ նշանակում է, որ խորհրդանիշն անտեսվում է համեմատության համապատասխան մակարդակում:

Կշեռքի կառուցվածքը ցուցադրելու համար ես ընտրեցի երեք բավականին ակնհայտ դրվագ.

  • կերպարներ, որոնք լիովին անտեսված են
  • առաջին երկու մակարդակներում երեք թվին համարժեք նշաններ
  • Կիրիլյան այբուբենի սկիզբը, որը չի պարունակում դիկրիտիկա, և, հետևաբար, դասավորված է հիմնականում առաջին և երրորդ մակարդակներով:

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

Քանի որ Unicode-ում Ё ծածկագրի կետը գալիս է A-ից առաջ, տողերը դասավորված են համապատասխանաբար:

Տեքստային և երկուական աղյուսակներ

Ակնհայտ է, որ տողերի համեմատությունը չափազանց տարածված գործողություն է և աղյուսակի վերլուծությունը CTT բավականին ծախսատար ընթացակարգ: Աղյուսակի հասանելիությունը օպտիմալացնելու համար այն հրամանի միջոցով կազմվում է երկուական ձևի localdef.

Թիմ localdef որպես պարամետրեր ընդունում է ազգային բնութագրերի աղյուսակով ֆայլ (տարբերակ -i), որտեղ բոլոր նիշերը ներկայացված են Յունիկոդ կետերով, և Յունիկոդ կետերի և կոնկրետ կոդավորման նիշերի միջև համապատասխանության ֆայլ (տարբերակ -f) Աշխատանքի արդյունքում վերջին պարամետրում նշված անունով լոկալի համար ստեղծվում են երկուական ֆայլեր։

Գլիբկ աջակցում է երկու երկուական ֆայլի ձևաչափեր՝ «ավանդական» և «ժամանակակից»:

Ավանդական ձևաչափը նշանակում է, որ տեղանքի անվանումը ենթագրքի անունն է /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/

Եթե ​​տեղայնացումը տեղի է ունենում ինչպես ավանդական, այնպես էլ ժամանակակից ձևաչափերով, ապա առաջնահերթությունը տրվում է ժամանակակիցին:

Հրամանով կարող եք դիտել կազմված տեղանքների ցանկը տեղական-ա.

Համեմատության աղյուսակի պատրաստում

Այժմ, զինված գիտելիքներով, դուք կարող եք ստեղծել ձեր սեփական իդեալական լարերի համեմատման աղյուսակը: Այս աղյուսակը պետք է ճիշտ համեմատի ռուսերեն տառերը, ներառյալ Ё տառը, և միևնույն ժամանակ հաշվի առնի կետադրական նշանները աղյուսակին համապատասխան: 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? Պատասխանը պարզ է. տեսակ համեմատում է ամբողջ տողը, և միանալ համեմատում է միայն բանալին, որը լռելյայնորեն տողի սկիզբն է մինչև առաջին բացատ նիշը: Իմ օրինակում դա հանգեցրեց սխալի հաղորդագրության, քանի որ տողերի առաջին բառերի տեսակավորումը չէր համընկնում ամբողջական տողերի տեսակավորման հետ:

Լոկալ «Գ» երաշխավորում է, որ տեսակավորված տողերում սկզբնական ենթատողերը մինչև առաջին բացատը նույնպես կտեսակավորվեն, բայց դա միայն քողարկում է սխալը: Հնարավոր է ընտրել տվյալներ (նույն ազգանուններով, բայց տարբեր անուններով մարդիկ), որոնք, առանց սխալի հաղորդագրության, սխալ ֆայլերի միաձուլման արդյունք կտան: Եթե ​​մենք ուզում ենք միանալ ֆայլի տողերը միաձուլվել են լրիվ անունով, ապա ճիշտ ճանապարհը կլինի հստակորեն նշել դաշտի բաժանարարը և տեսակավորել ըստ հիմնական դաշտի, այլ ոչ թե ամբողջ տողի: Այս դեպքում միաձուլումը ճիշտ կշարունակվի, և որևէ տեղանքում սխալներ չեն լինի.

$> 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 թողարկում է ֆայլեր, որոնք սկսվում են տառով սկսվող ֆայլերով խառնված կետով և Կեսգիշեր հրամանատար, որն օգտագործում է իր ներքին գործառույթները անունները տեսակավորելու համար, ցուցակի սկզբում դնում է կետով սկսվող ֆայլերը։

Սայլակ

Հաշվետվություն թիվ 10 Յունիկոդի համադրման ալգորիթմ

Նիշերի կշիռները unicode.org-ում

ICU — IBM-ից Unicode-ի հետ աշխատելու համար գրադարանի ներդրում:

Տեսակավորման թեստ օգտագործելով ICU

Նիշերի կշիռները ISO 14651

Ֆայլի ձևաչափի նկարագրությունը մասշտաբներով ISO 14652

Տողերի համեմատության քննարկում glibc

Source: www.habr.com

Добавить комментарий