(Dovrebbe) LC_COLLATE influisce sugli intervalli di caratteri?


27

L' ordine di confronto attraverso LC_COLLATEdefinisce non solo l'ordinamento dei singoli caratteri, ma anche il significato delle gamme di caratteri. O lo fa? Considera il seguente frammento:

unset LANGUAGE LC_ALL
echo B | LC_COLLATE=en_US grep '[a-z]'

Intuitivamente, Bnon è presente [a-z], quindi questo non dovrebbe produrre nulla. Questo è ciò che accade su Ubuntu 8.04 o 10.04. Ma su alcune macchine che eseguono Debian Lenny o squeeze, Bsi trova, perché la gamma a-zinclude tutto ciò che è tra le ae znell'ordine collazione, incluse le lettere maiuscole Battraverso Z.

Tutti i sistemi testati hanno la en_USlocalizzazione generata. Ho anche provato a variare le impostazioni locali: sulle macchine in cui Bè presente la corrispondenza sopra, lo stesso accade in tutte le {en_{AU,CA,GB,IE,US},fr_FR,it_IT,es_ES,de_DE}{iso8859-1,iso8859-15,utf-8}impostazioni locali disponibili (principalmente in latino:, anche in cinese) eccetto il giapponese (in qualsiasi codifica disponibile) e C/ POSIX.

Cosa significano le gamme di caratteri nelle espressioni regolari , quando vai oltre ASCII? Perché c'è una differenza tra alcune installazioni Debian da un lato e altre installazioni Debian e Ubuntu dall'altro? Come si comportano gli altri sistemi? Chi ha ragione e chi dovrebbe avere un bug segnalato contro?

(Si noti che sto specificatamente chiedendo informazioni sul comportamento degli intervalli di caratteri, ad esempio [a-z]nelle en_USversioni locali, principalmente sui sistemi basati su libc GNU. Non sto chiedendo come abbinare le lettere minuscole o le lettere minuscole ASCII.)


Su due macchine Debian, una in cui si Btrova [a-z]e una in cui non lo è, l'output di LC_COLLATE=en_US locale -k LC_COLLATEè

collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=1
collate-codeset="ISO-8859-1"

e l'output di LC_COLLATE=en_US.utf8 locale -k LC_COLLATEè

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

1
Non si riproduce su un'istanza di Debian Lenny che ho avuto a portata di mano. en_USTuttavia, non ho verificato se è stato generato.
alex

1
@alex Se la locale non viene generata, la Clocale viene utilizzata come fallback e il suo ordine di confronto è costituito da valori di byte diretti, quindi Bnon verrà abbinato. Test in una locale che appare nell'output di locale -a.
Gilles 'SO- smetti di essere malvagio' il

1
Si noti che en_US NON è uguale a en_US.utf8 e in genere significa en_US.iso-8859-1, a seconda di ciò che è stato installato. Se en_US (senza suffisso) non viene visualizzato nell'output della locale -a non si ha effettivamente questa locale. Cosa mostra LC_COLLATE = en_US locale -k LC_COLLATE?
Neil Mayhew,

1
Da allora questo è emerso in una domanda pratica piuttosto che teorica qui: perché le lettere maiuscole sono incluse in una serie di lettere minuscole in una regex awk?
Caleb,

1
@isaac Sfortunatamente, 7 anni dopo, non ho accesso a nessun sistema problematico. Sono stati tutti aggiornati o disattivati.
Gilles 'SO- smetti di essere malvagio'

Risposte:


3

Se stai usando qualcosa di diverso dalla Clocale, non dovresti usare intervalli come [a-z]questi poiché dipendono dalla locale e non sempre danno i risultati che ti aspetteresti. Oltre al problema del caso che hai già riscontrato, alcune versioni locali trattano i personaggi con segni diacritici (ad es. Á ) allo stesso modo del carattere di base (ovvero a ).

Invece, usa una classe di caratteri con nome:

echo B | grep '[[:lower:]]'

Ciò fornirà sempre il risultato corretto per la locale. Tuttavia, è necessario scegliere le impostazioni internazionali per riflettere il significato sia del testo di input sia del test che si sta tentando di applicare.

Ad esempio, se è necessario trovare un determinato valore byte, utilizzare la Clocale, che è sempre disponibile:

echo B | LANG=C grep '[a-z]'

Se questo non funziona come previsto, è davvero un bug.


Lo so, non è quello che ho chiesto. Chiedo in particolare cosa significhi un intervallo esplicito e perché diverse distribuzioni (anche con GNU libc e GNU grep) hanno comportamenti diversi. (Sottovalutato perché anche se quello che dici è corretto, è irrilevante.)
Gilles 'SO- smetti di essere malvagio'

1
Il mio punto è che il significato di un intervallo esplicito dipende dalle impostazioni locali e che non è necessario che sistemi diversi definiscano le loro impostazioni locali allo stesso modo, quindi non si tratta di un bug. Tecnicamente, stai abusando del sistema, quindi non dovresti essere sorpreso di ottenere un comportamento "indefinito". Inoltre, diverse persone hanno commentato che non possono riprodurre il comportamento sui loro sistemi Debian, quindi sembra che ci sia qualcosa di insolito nei vostri sistemi.
Neil Mayhew,

1
So che il comportamento degli intervalli dipende dalle impostazioni locali. Mi chiedo come, e sono sorpreso che diversi sistemi che usano Glibc (e, a quanto pare, anche diverse installazioni della stessa versione di Debian) abbiano comportamenti diversi. Ho aggiunto l'output di locale -kalla mia domanda; è identico su due macchine Debian, una in cui si Btrova nell'intervallo e una in cui non lo è. A proposito, non sono root su nessuna macchina (quindi non è qualcosa di strano che faccio come amministratore).
Gilles 'SO- smetti di essere malvagio' il

echo "Baü" | LC_COLLATE=C grep -o '[[:lower:]]'restituisce aE ümentre echo "Baü" | LC_COLLATE=C grep -o '[a-z]'restituisce solo a. Ai miei occhi, "inferiore" non è proprio quello che voleva l'OP
Daniel Alder,

Il mio punto originale è ancora valido: non usare gli intervalli a meno che non ci si trovi nella Clocale. Credo che ciò sia rilevante per l'OP, che stava cercando di segnalare un bug. Se non ci si trova nelle Cimpostazioni internazionali, i risultati dell'utilizzo degli intervalli sono altamente imprevedibili e pertanto non possono mai essere considerati un bug. D'altra parte, se è necessario trovare un determinato valore di byte, utilizzare solo la Clocale. Il mio punto secondario era che se vuoi davvero cercare lettere minuscole in una locale, usa una classe di caratteri. Anche se l'OP potrebbe non averlo cercato, altri potrebbero trovare questa domanda.
Neil Mayhew,

1

Gli intervalli nelle espressioni regolari devono osservare l'impostazione delle regole di confronto. Ecco lo standard pertinente: http://pubs.opengroup.org/onlinepubs/007908799/xbd/re.html (cercare "espressioni di intervallo"). Quindi echo B | LC_COLLATE=en_US grep '[a-z]'dovrebbe essere Bdata una definizione ragionevole delle rispettive impostazioni locali. Non posso spiegare perché a volte questo non funzioni per te, ma sarei molto sorpreso se lo incontrassi su un sistema non antico che è installato e configurato correttamente.


1
echo B | LC_COLLATE=en_US.utf8 grep '[a-z]' Non stampa nulla su Ubuntu 12.04 con grep 2.10. Non stampa nulla su Centos 6.5 con grep 2.6.3. Funziona su Debian 6.0.8 con grep 2.6.3.
Ian D. Allen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.