Куди пішов мій рядок `uniq` або` sort -u`, з деякими символами unicode


10

Що відбувається в наступному фрагменті коду? Я не отримую очікуваного результату.

Я думаю, що це помилка, але це трапляється для двох різних програм (uniq і сортування), тому я підозрюю, що це щось стосується ... ну, я не знаю, що .. звідси питання.

Перші 3 (із 4) прикладів працюють, але 4-й не вдається !.

Я б очікував однакової поведінки для всіх персонажів.
тобто. роздрукувати 2 рядки (з 3 рядків введення) ... але в 4-му випадку я отримую лише 1 рядок (і для обох, sort -uі для uniq); обидва однакові кришки просто зникають!

Я перетворив висновок '\ n' у простір для компактності перегляду.

Я використовую uniq і сортую з (GNU coreutils) 7.4 ..., що працює на робочому столі Ubuntu 10.04.3 LTS.

Сценарій:

{
  locale -k LC_COLLATE
  echo
  for c1 in x 〼 ;do 
    for c2 in z 〇 ;do 
      echo -n "asis   : "; echo -e "$c1\n$c2\n$c2"          |tr '\n' ' ';echo
      echo -n "uniq   : "; echo -e "$c1\n$c2\n$c2" |uniq    |tr '\n' ' ';echo
      echo -n "sort -u: "; echo -e "$c1\n$c2\n$c2" |sort -u |tr '\n' ' ';echo
      echo
    done
    echo
  done
}

Вихід:

collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=2081
collate-codeset="UTF-8"

asis   : x z z 
uniq   : x z 
sort -u: x z 

asis   : x 〇 〇 
uniq   : x 〇 
sort -u: 〇 x 


asis   : 〼 z z 
uniq   : 〼 z 
sort -u: 〼 z 

asis   : 〼 〇 〇 
uniq   : 〼 
sort -u: 〼 

# In the last example (of 4) where did the '〇' go? .. U+3007 IDEOGRAPHIC NUMBER ZERO
#

Зверніть увагу . Щоб це було зрозуміло. sortпоодинці (без опції -u ) ... не збиває символів. Що входить, виходить ... Однак, як можна очікувати поясненням Гілла про "екзотичні" символи унікоду, що мають однакове канонічне значення , ці символи не сортуються, за винятком того, що вони виводяться як несортована група FIFO до "вершини" виводу сортування ... Отже, тут справді два питання: 1. Персонажі не сортуються так, як могли б бути "наївно" "очікуваного та 2." Унікальна "особливість sortі uniqвтрачає дані (в деяких випадках).
Пітер.O

Оновлення: Як згадував Жил (коли сортування для певного локального значення не є важливим, і порядок символів підходить), sort -uі uniqпрацюйте добре з: LC_COLLATE=C; echo -e "〼\n〇\n〇" |sort -u(або |uniq)
Peter.O

Відповіді:


11

Коротка версія: порівняння насправді не працює в утилітах командного рядка.

Більш дрібна версія: основна функція для порівняння двох рядків є strcoll. Опис не дуже корисний, але концептуальним методом операції є перетворення обох рядків у канонічну форму, а потім порівняння двох канонічних форм. Функція strxfrmбудує цю канонічну форму.

Давайте спостерігатимемо канонічні форми декількох рядків (з GNU libc, під стисканням Debian):

$ export LC_ALL=en_US.UTF-8
$ perl -C255 -MPOSIX -le 'print "$_ ", unpack("h*", strxfrm($_)) foreach @ARGV' b a A à 〼 〇
b d010801020
a c010801020
A c010801090
à 101010102c6b
〼 101010102c6b102c6b102c6b
〇 101010102c6b102c6b102c6b

Як бачимо, 〼 і 〇 мають однакову канонічну форму. Я думаю, що це тому, що ці символи не згадуються в таблицях зіставлення в en_US.UTF-8локалі. Однак вони присутні в японській місцевості.

$ export LC_ALL=ja_JP.UTF-8
$ perl -C255 -MPOSIX -le 'print "$_ ", unpack("h*", strxfrm($_)) foreach @ARGV' 〼 〇 
〼 303030
〇 3c9b

Вихідний код для даних локалів (в стислі Debian), в /usr/share/i18n/locales/en_USякий входить /usr/share/i18n/locales/iso14651_t1_common. У цьому файлі немає запису для, U3007або U303Cвони не включаються в будь-який діапазон, який я можу знайти.

Я не знайомий з правилами побудови порядку порівняння , але з того, що я розумію, є відповідне словосполучення

Символ НЕ ВИЗНАЧЕНИЙ тлумачиться таким, що включає всі кодовані значення набору символів, не визначені явно або через символ еліпсису. (…) Якщо не визначено НЕ визначений символ, а поточний кодований набір символів містить символи, не зазначені в цьому розділі, утиліта видає попереджувальне повідомлення та розміщує такі символи в кінці порядку порівняння символів.

Схоже, Glibc замість цього ігнорує символи, які не вказані. Я не знаю, чи є недолік у моєму розумінні специфікації POSIX, якщо я пропустив щось у визначенні локальної точки Glibc, чи є помилка у компіляторі локалізації Glibc.


@Gilles: Дякую за інформативне та детальне пояснення .. Це має певний сенс зараз, але мені залишається цікаво, як "безпечно" використовувати сорт . Я не після особливо "чутливого до локального" сорту, тому будь-який грубий сортування зробить ... Чи для цього є швидке вирішення? ... і я поступово розберуся на це, але це не відбудеться "протягом ночі" ... наприклад .. мій / usr / share / i18n / charmaps / UTF-8 містить посилання на обох відповідних символів. , але, описуючись у цьому визначенні UTF-8 (?), схоже, не допомагає ... О, як би виглядало життя без маленьких загадок. :) ...
Пітер.О

1
@fred charmaps/UTF-8нічого не говорить про порівняння, це locales/en_USважливо. Перше правило LC_COLLATE: не користуватися LC_COLLATE. У мові C (= POSIX) порівняння є розумним (засноване строго на числових значеннях символів).
Жил 'SO- перестань бути злим'

2
В сортувальних і унікальний аспект роботи добре , коли передує LC_COLLATE=C... спасибі ...
Peter.O

1
Справа не в тому, що співставлення не працює в утилітах, але що локалі glibc погано розроблені. Така поведінка (наразі, але див. Austingroupbugs.net/view.php?id=1070 ) дозволена POSIX, але прикрою та небажаною.
Стефан Шазелас

6

Щоб "безпечно" sortрядки Unicode, можливо, подивіться на msort:

[...] Msort забезпечує більшу гнучкість у виборі ключових полів, більше типів порівняння, можливість використання правил зіставлення з різних локалів на різних клавішах, можливість обробки чисел у незахідних системах числення та безліч інших варіантів, яких не вистачає у сортуванні GNU та BSD. Тоді як msort розуміє Unicode, GNU сортування та BSD сортування не роблять. [...]

http://www.billposer.org/Software/msort.html


@til: Дякую за те, що ти мене обізнавmsort . Необов'язковий графічний інтерфейс робить вступ трохи легшим, щоб відчути, що пропонується. Бути в змозі скопіювати згенеровану команду дуже зручно ... І так, вона сортує символи unicode, але (хіба ви просто не любите ці "buts":) ... але у неї немає унікальної опції: (... як згадувалося у посиланні, яке ви опублікували: Capabilities of GNU sort and BSD sort lacking in msort are the ability to merge files without sorting them (the --merge option) and the ability to emit only the first of an equal run (the --unique option)... Цей сорт працює, хоча :)
Peter.O
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.