Urutan koleksi melalui LC_COLLATE
mendefinisikan tidak hanya urutan urutan karakter individu, tetapi juga arti rentang karakter. Atau apakah itu? Pertimbangkan cuplikan berikut:
unset LANGUAGE LC_ALL
echo B | LC_COLLATE=en_US grep '[a-z]'
Secara intuitif, B
tidak ada [a-z]
, jadi ini seharusnya tidak menghasilkan apa-apa. Itulah yang terjadi di Ubuntu 8.04 atau 10.04. Tetapi pada beberapa mesin yang menjalankan Debian lenny atau squeeze, B
ditemukan, karena jangkauan a-z
mencakup semua yang ada di antara a
dan z
dalam urutan pemeriksaan, termasuk huruf kapital yang B
dilalui Z
.
Semua sistem yang diuji memang memiliki en_US
lokal yang dihasilkan. Saya juga mencoba memvariasikan lokal: pada mesin B
yang cocok di atas, hal yang sama terjadi di setiap lokal yang tersedia (kebanyakan berbasis latin:, {en_{AU,CA,GB,IE,US},fr_FR,it_IT,es_ES,de_DE}{iso8859-1,iso8859-15,utf-8}
juga lokal Cina) kecuali Jepang (dalam penyandian yang tersedia) dan C
/ POSIX
.
Apa arti rentang karakter dalam ekspresi reguler , ketika Anda melampaui ASCII? Mengapa ada perbedaan antara beberapa instalasi Debian di satu sisi, dan instalasi Debian lainnya dan Ubuntu di sisi lain? Bagaimana sistem lain berperilaku? Siapa yang benar, dan siapa yang seharusnya melaporkan bug?
(Perhatikan bahwa saya secara khusus bertanya tentang perilaku rentang karakter seperti [a-z]
di en_US
lokal, terutama pada sistem berbasis libc GNU. Saya tidak bertanya bagaimana mencocokkan huruf kecil atau huruf kecil ASCII.)
Pada dua mesin Debian, satu di mana B
ada [a-z]
dan satu di mana tidak, output dari LC_COLLATE=en_US locale -k LC_COLLATE
adalah
collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=1
collate-codeset="ISO-8859-1"
dan output dari LC_COLLATE=en_US.utf8 locale -k LC_COLLATE
is
collate-nrules=4
collate-rulesets=""
collate-symb-hash-sizemb=2039
collate-codeset="UTF-8"
sumber
en_US
dihasilkan.C
lokal digunakan sebagai fallback, dan urutan susunannya adalah nilai byte langsung, jadiB
tidak akan cocok. Tes di lokal yang muncul di outputlocale -a
.Jawaban:
Jika Anda menggunakan sesuatu selain
C
lokal, Anda tidak boleh menggunakan rentang seperti[a-z]
karena ini bergantung pada lokal dan tidak selalu memberikan hasil yang Anda harapkan. Seperti halnya kasus yang Anda temui, beberapa lokal memperlakukan karakter dengan diakritik (misalnya á ) sama dengan karakter dasar (yaitu a ).Sebagai gantinya, gunakan kelas karakter bernama:
Ini akan selalu memberikan hasil yang benar untuk lokal. Namun, Anda harus memilih lokal untuk mencerminkan arti dari teks input dan tes yang Anda coba terapkan.
Misalnya, jika Anda perlu menemukan nilai byte tertentu, gunakan
C
lokal, yang selalu tersedia:Jika ini tidak berfungsi seperti yang diharapkan, itu benar-benar bug.
sumber
locale -k
ke pertanyaan saya; itu identik pada dua mesin Debian, satu di manaB
berada dalam kisaran dan satu di mana tidak. BTW Saya tidak melakukan root pada salah satu mesin (jadi itu bukan sesuatu yang aneh yang saya lakukan sebagai admin).echo "Baü" | LC_COLLATE=C grep -o '[[:lower:]]'
mengembalikana
ANDü
sementaraecho "Baü" | LC_COLLATE=C grep -o '[a-z]'
hanya mengembalikana
. Di mata saya, "lebih rendah" sebenarnya bukan yang diinginkan OPC
lokal. Saya percaya ini relevan dengan OP, yang ingin melaporkan bug. Jika Anda tidak berada diC
lokal, hasil menggunakan rentang sangat tidak terduga dan karenanya tidak pernah dapat dianggap sebagai bug. Di sisi lain, jika Anda perlu menemukan nilai byte tertentu, cukup gunakanC
lokal. Poin kedua saya adalah jika Anda benar-benar ingin mencari huruf kecil di lokal, gunakan kelas karakter. Meskipun OP mungkin tidak mencari ini, orang lain mungkin jika mereka menemukan pertanyaan ini.Kisaran dalam ekspresi reguler harus memperhatikan pengaturan collation. Berikut adalah standar yang relevan: http://pubs.opengroup.org/onlinepubs/007908799/xbd/re.html (lihat "rentang ekspresi"). Jadi
echo B | LC_COLLATE=en_US grep '[a-z]'
seharusnya outputB
diberikan definisi yang masuk akal dari masing-masing lokal. Saya tidak bisa menjelaskan mengapa ini kadang-kadang tidak berhasil untuk Anda, tetapi saya akan sangat terkejut jika saya menemukan ini pada sistem non-kuno yang diinstal dan dikonfigurasi dengan benar.sumber
echo B | LC_COLLATE=en_US.utf8 grep '[a-z]'
Tidak mencetak apa pun di Ubuntu 12.04 dengan grep 2.10. Tidak mencetak apa pun di Centos 6.5 dengan grep 2.6.3. Bekerja pada Debian 6.0.8 dengan grep 2.6.3.