Bash

Bash 和 Zsh 如何處理模式和正則表達式中的排序規則?

  • April 18, 2021

考慮以下範例:

$ bash --version
GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ LC_COLLATE=C bash --norc -c '[[ B == [a-z] ]] && echo yes || echo no'
no
$ LC_COLLATE=en_GB bash --norc -c '[[ B == [a-z] ]] && echo yes || echo no'
yes
$ LC_COLLATE=C bash --norc -c '[[ B =~ [a-z] ]] && echo yes || echo no'
no
$ LC_COLLATE=en_GB bash --norc -c '[[ B =~ [a-z] ]] && echo yes || echo no'
no

似乎在與模式匹配時(即使用=or ==),Bash 根據 LC_COLLATE 進行整理;但是,當與正則表達式匹配(即使用=~)時,Bash 會根據 POSIX 或類似的東西進行整理。

zsh 5.8.0.2-dev (x86_64-pc-linux-gnu)Zsh——至少——no在所有情況下都會列印。

是否可以保證[a-z]在模式或正則表達式中使用時會完全匹配什麼?

不,不能保證完全[a-z]匹配,期間。

好吧,在任何其他語言環境中"C"(當實用程序符合 POSIX 時)。

核心問題在於“範圍”表達式(使用-)。

像這樣的顯式列表[abcdefghijklmnopqrstuvwxyz]永遠不會失敗。


POSIX 請求a-z完全是abcdefghijklmnopqrstvwxyz,是的,但僅當語言環境是 POSIX 預設值時,即:"C"

從 POSIX 規範:

在 POSIX 語言環境中,範圍表達式表示位於歸類序列中兩個元素之間的歸類元素集,包括兩個元素。在其他語言環境中,範圍表達式具有未指定的行為:嚴格符合的應用程序不應依賴範圍表達式是否有效,或匹配的排序元素集。範圍表達式應表示為由(’-’)分隔的起點和終點。

即使 POSIX 要求a-z任何應用程序具有特定含義,也可能會選擇簡單地忽略 POSIX。

只是為了展示冰山一角:

Python 2.7 僅匹配 ASCII,a-z但 Python 3.0 將匹配許多其他 Unicode 字元。Bash 過去只匹配 ASCII 到 3.2 版本。然後它決定在應用的語言環境中匹配在和之間排序的字元,其中可能包括(通常不包括)。現在,在 bash 版本 5.0+ 中,可以使用 globasciiranges 選項來配置範圍,預設情況下,該選項是打開的,意圖主要匹配ASCII字元。a``z``A-Y``Z``a-z

$ LC_COLLATE=en_GB bash -c 'shopt -u globasciiranges; [[ B == [a-z] ]] && echo yes || echo no'
yes

$ LC_COLLATE=en_GB bash -c 'shopt -s globasciiranges; [[ B == [a-z] ]] && echo yes || echo no'
no

但即使 bash 5.0 和 globasciiranges 處於活動狀態,它== [a-z]也會匹配 en_GB.utf-8 語言環境中的 2190 個字元。只是為了讓您理解,這是a允許的 -like 字元列表:

a a ͣ ⒜ 𝐚 𝑎 𝒂 𝒶 𝓪 𝔞 𝕒 𝖆 𝖺 𝗮 𝘢 𝙖 𝚊 ⓐ A 🄐 𝐀 𝐴 𝑨 𝒜 𝓐 𝔄 𝔸 𝕬 𝖠 𝗔 𝘈 𝘼 𝙰 Ⓐ 🅐
ᵃ ₐ ᴬ 🄰 🅰 ă Ă ắ Ắ ằ Ằ ẵ Ẵ ẳ Ẳ ấ Ấ ầ Ầ ẫ Ẫ ẩ Ẩ ǎ Ǎ Å ǻ Ǻ ᷲ ꞛ Ꞛ ǟ Ǟ ȧ Ȧ ǡ Ǡ ą
Ą ā Ā ả Ả ȁ Ȁ ȃ Ȃ ạ Ạ ặ Ặ ậ Ậ ḁ Ḁ ᷓ ꜳ Ꜳ 🆎 ℀ ᷔ ᴭ ǽ Ǽ ǣ Ǣ ㏂ ㏟ ᷕ ꜵ Ꜵ ℁ ⅍
ꜷ Ꜷ ㍳ ᷖ ꜹ Ꜹ ꜻ Ꜻ ꜽ Ꜽ ẚ ᴀ ⱥ Ⱥ ᶏ ᴁ ᴂ ᵆ ꬱ ɐ Ɐ ᵄ ɑ ᷧ Ɑ ᵅ ꬰ ᶐ ɒ Ɒ ᶛ ꭤ 

如果測試是 ,則匹配的字元數變為 1368 個字元=~ [a-z]。即更改為正則表達式會更改匹配字元的列表。

但是,在C語言環境中(對於 bash),只有 26 個字母匹配(或者===~)。

zsh

現在,zsh 被設置為將測試字元的 wchar_t 表示的數值與右側的數值範圍進行比較:

[[ "$c" == [a-z] ]]

但是,這是什麼意思?

  1. 在 ASCII、iso-8859 和 UTF-8 中,它通常意味著 wchar_t 的數值與charmap 的數值相同。

一個。我們程序員應該已經知道 ASCII 編號。並且沒有特別的理由為什麼@應該排序#,只是運氣。

灣。作為 iso-8859 問題的一個實際範例:在 iso-8859-1 和 iso-8859-15中¾Ÿ具有相同的數值。那應該如何解決?

C。Unicode 中字元的數字位置通常遵循age的位置。較舊的字元通常比較新的字元具有較低的數值。A ñ( \u00f1),西班牙字元不包含在a-z字元範圍 ( \u0061- \u007a) 中。任何講西班牙語的人都會說應該。

$ LC_ALL=es_ES.UTF-8  zsh -c '[[ ñ == [a-z] ]] && echo yes || echo no'
no

但令人震驚的是,它是德文的:

$ LC_ALL=de_DE.UTF-8  zsh -c '[[ ñ =~ [a-z] ]] && echo yes || echo no'
yes
  1. 但是(就像 zsh 的粉絲 Stéphane Chazelas 一樣)說過:

另一個問題是,在使用 ASCII、ISO-8859-1 或 UTF-8 字元映射的語言環境之外,行為因係統而異,因為並非所有系統都實現 wchar_t 相同。

In fact, what a wchar means is [compiler dependent][4]:

wchar_t 依賴於編譯器,因此不是很便攜。將它用於 Unicode 會將程序綁定到編譯器的字元模型。將它用於 Unicode 會將程序綁定到編譯器的字元模型。

  1. 而且,更一般地說,wchar 不需要使用 Unicode,根本不需要。那麼:為什麼要使用它?我在這裡使用名稱 Unicode 作為所有現有字元的意思。

咆哮模式開啟


對不起,但我必須抱怨,我需要把這個從我的胸膛裡拿出來。

是的,(對於程序員)範圍 az 表示一個穩定且最好是小的字元列表是有用的。是的,小寫字母的 ASCII 列表似乎是一個合理的(即使是幼稚的)解決方案。是的,情況與

$$ a-z $$匹配 2190 個字元,很容易從一個版本更改為下一個版本,如上所示,對於程序員和開發的應用程序的安全性來說是一個巨大的問題。 但是強制每個地方的每個人都只能在任何語言環境中匹配 26 個字母(現在 POSIX 的意圖是建立

$$ a-z $$將僅匹配****任何語言環境中的 ASCII 小寫字母)非常幼稚,並且過度簡化了手頭的問題。

程式碼頁

有一種想法是在程式碼頁(通常為 256 個字元的列表)中編碼語言,最早的程式碼頁之一是 ASCII(只有 128 個字元)。它只是美式英語。

但是美式英語只有 3.69 億人,世界其他地方,世界 95% 的人,與這個描述不符。僅將其擴展到美國其他地區,美國的西班牙-葡萄牙語(超過 6.5 億)部分,使得英語僅占美國的 36%。

ASCII 被擴展以涵蓋不同的語言。所以有一個西里爾字母的程式碼頁,一個希伯來語的程式碼頁,一個包含西班牙語的程式碼頁,一個包含ñ葡萄牙語的程式碼頁ç,等等。但這意味著你不能同時****用希伯來語西里爾字母寫字母。

然後出現了 16 位就足夠的想法。這種方法奏效了一段時間,直到我們從中國獲得了 50.000 個字元。一些解決方案試圖將所有這些字元硬塞到 16 位中。但這沒有任何希望。

那沒有用,就像“誰需要比 640K 更多的記憶體?” 沒用。

UTF-8

然後,感謝上帝,網路接受了 UTF-8,語言變得更容易了。UTF-8 直接覆蓋所有 1.114.112(如果需要,還可以更多)可能的 UCS2 Unicode 程式碼點 (17 * 2^16)。是的,只有143,859 個字元,已分配 Unicode 13.0(是的,包括所有中文)。

讓我們理解它:有很多語言!

觀點很多!!!

程序員

我們,程序員(包括我自己在內),肯定會喜歡每個人都知道 ASCII 並且只有 26 個字母(一直)匹配

$$ a-z $$. 但這不是我們生活的世界。大多數人(我猜世界人口的 99.9% 不是程序員)不了解 ASCII。但是大多數會讀寫的人都知道字典是什麼。整理順序主要是字典順序。 我確信希臘的字典不使用 az 作為主要條目。世界上大部分地區都可以重複這種情況。

我們需要增長到超過 26 個字母的a-z範圍。

我們要麼接受變革,要麼將其從外部強加給我們,帶來好的和壞的後果。我們最好找到解決辦法。

我可以考慮[ascii:a-z]在任何語言環境中僅對 26 個 ASCII 字母使用或類似的東西,甚至C. 是的,它不是:向後兼容,但我們已經處於問題的中間,一個不向後兼容的問題,[a-z]在 bash 中幾乎可以處理任何事情。

這將允許[french:a-z]例如 and [greek:a-z], and/or

$$ greek:α-ω $$並期望對該語言的使用者有意義。並且[a-z]將保留為我們已經獲得的所有語言範圍(是的,它恰好是向後兼容的)。


咆哮模式關閉


引用自:https://unix.stackexchange.com/questions/645054