作者
Patrik Nyblom <pan(at)erlang(dot)org> , Fredrik Svahn <Fredrik(dot)Svahn(at)gmail>
狀態
草案
類型
標準追蹤
建立於
2010年9月29日
Erlang 版本
OTP_R14B
取代
9

EEP 35:二進制字串模組 #

摘要 #

此 EEP 包含了關於 binary_string 模組的建議,該模組最初在 EEP 9 中提出。然而,模組名稱現在已變更為 bstring

EEP 9 提出了數個模組,並且部分被後來的 EEP 所取代(例如 EEP 11EEP 31),同時仍然包含尚未實作的寶貴建議。因此,EEP 9 中最後剩下的模組建議將在此單獨的 EEP 中出現。這是與 EEP 9 的原始作者達成協議後進行的。

建議 bstring 模組包含用於方便操作以二進制格式儲存的文字資料(即二進制字串)的函數。它在某種程度上類似於 string 模組(以列表為導向),但不應僅僅將其視為二進制的 string 模組。

建議的模組處理 Erlang 標準字元編碼中的二進制字元編碼,即 ISO-Latin-1 和 UTF-8。

動機 #

文字字串傳統上在 Erlang 中表示為整數列表。雖然這很方便並且或多或少內建於語言的語法中(例如,“ABC” 是 [$A,$B,$C] 的語法糖),但通常需要更緊湊的表示形式。此外,在某些情況下,就演算法複雜度而言,二進制比列表更有效率(尤其是在 ISO-Latin-1 的固定字元寬度情況下)。

最近在標準函式庫中新增了更多模組,以幫助使用二進制來表示文字字串,包括表示 ISO-Latin-1 字元和以 UTF-8 編碼的 Unicode 字串。最值得注意的是 re 函式庫,但 unicode 模組也是 stdlib 中相當新的新增功能,這將使程式設計師在操作二進制編碼的字串時更加輕鬆。此外,還存在一個用於在位元組導向二進制中快速搜尋和取代的模組(binary 模組),但函式庫中尚未有傳統的字串操作模組。為了方便使用二進制編碼的字串,需要這樣一個模組。

基本原理 #

用於列表文字導向操作的 string 模組在標準函式庫中存在了很長時間,以至於大多數程式設計師都不記得它不存在的時候。據說它最初是兩個不同字串模組的合併,由兩個不同的程式設計師編寫和設計,他們可能具有略有不同的目標,並且絕對對函數命名有略有不同的看法。雖然有時會因重複的功能和不一致的函數命名等問題而受到批評,但該模組在 Erlang/OTP 的整個生命週期中仍然很有用。使用的字串表示形式也經受住了 Unicode 的發展。

值得注意的是,string 模組中唯一實際上與語言或地區相關的函數是後來新增到該模組的函數。這些函數(如 to_upperto_lowerto_integerto_float)或它們的二進制對應項,並不是我建議用於 bstring 的模組介面的一部分,原因很簡單,它們需要 Erlang 中尚未提供的語言支援。未來的 EEP 可能會建議此類語言支援(即某種「地區設定」支援),但這是此 EEP 未涵蓋的未來工作。

因此,無論受到多少批評,字串模組對於操作列表都非常有用,並且希望二進制字串也具有相同的功能。雖然許多功能將相似,但在實作用於操作二進制編碼字串的模組時,需要考慮一些主要問題

  • Unicode - 二進制可以具有不同的編碼。以 UTF-8 編碼的字元可能佔用多個(最多四個)位元組位置,甚至相同的字元在 ISO-Latin-1 和 UTF-8 中可能具有不同的編碼(所有碼位從 128 到 255)。函數需要明確地知道字元編碼。編碼資訊不存在於二進制中。

  • 混合字元編碼 - 由於字元可以用不同的方式編碼,因此同一個程式中的兩個字串可能具有不同的編碼。在整個模組中,應一致地解決為函數提供非同質字串編碼資料的問題,並且應在適用的情況下選擇返回的編碼。

  • 預設字元編碼 - 由於函數將使用額外的參數來指定編碼,因此一致的預設值可能很有用。選擇預設值並非完全簡單,因為傳統上使用 ISO-Latin-1,而未來建議使用 UTF-8。

  • 語言 - Erlang 沒有「地區設定」或偏好的數字格式的概念。通用的字串模組既不能假定特定的的大寫或小寫字母概念,也不能假定特定的數字編碼格式(對於浮點數而言尤其如此)。

  • 單字分隔符 - 空格字元當然不是文字資料(以任何語言)中唯一的單字分隔符。以空格分隔的單字概念對相關語言施加了限制。

  • 由左至右或由右至左 - 像左或右這樣表示字串開頭或結尾的概念肯定不是與語言無關的。雖然語言中的字串具有開頭和結尾,但該開頭和結尾可以放置在圖形表示的左側、右側,甚至頂部、底部或中心。字串操作模組不應使用暗示由左至右的腳本或任何其他類型腳本的命名。

  • 命名和重複功能 - 原始的 string 模組被指責為命名和功能重複有些不一致。事實上,唯一重複的函數是 substrsub_string。可能需要清理介面。

  • 位元組導向與字元導向的傳回值 - 在處理 Unicode 資料時,字元可能佔用多個位元組,這就是為什麼計算字串中的字元數對您而言,對於字串的實際位元組大小而言,幾乎沒有說明。此外,稍後處理二進制可能需要對字串進行位元組導向的操作,而不是字元導向的操作(即,您希望使用 binary 模組或位元語法來操作字串),而字元實際上是構成字串的元素,而不是位元組。您兩種都想要。

  • 新增或取代的功能 - 從多個來源(最值得注意的是 EEP 9)提出新的功能。例如,EEP 9 中建議的 split 函數與

    string:tokens/2

    非常相似。我們是否應該無論如何都保留 tokens,例如?

我將在下面說明不同的問題。

Unicode #

介面必須同時支援 ISO-Latin-1 和 UTF-8。unicode 模組支援更多編碼,但 Erlang/OTP 將 UTF-8 用於所有「內部」介面,並且 UTF-8 是二進制 Unicode 字串的預期編碼。即使 UTF-8 與 7 位元 ASCII 範圍內的 ISO-Latin-1 相容,但碼位介於 128 和 255 之間的字元在「純」ISO-Latin-1 編碼和 UTF-8 中的編碼方式不同。這表示 bstring 模組中的所有函數都需要將實際編碼作為一個或多個額外參數。

人們可以發明更抽象的二進制字串格式,其中資料例如表示為一個包含字串和編碼的元組。然而,沒有其他模組支援此類字串結構,而且我不認為這會真正新增任何東西,無論是功能還是可讀性。考慮像這樣的程式碼

bstring:tokens(Bin,latin1,[$ ,$\n])

相較於

bstring:tokens({Bin,latin1}, [$ ,$\n]).

甚至

bstring:tokens(#bstring{data = Bin, encoding = latin1}, [$ ,$\n]).

在許多情況下,需要在呼叫時新增額外資訊,這使得程式碼的可讀性或編寫簡單程度不高於使用單獨的額外參數。考慮一下我們是否有編碼的預設值。程式碼

f(Data) ->
    bstring:tokens(Data,[$ ,$\n]).

不會以任何方式指示 Data 應該是具有預設編碼的二進制,還是某種表示實際字串及其編碼的複雜資料結構。

我認為編碼的額外參數簡單明瞭,並且在使用其他模組中的二進制字串時(即 rebinaryfile 等),它使程式設計更容易。我認為我們不應該僅為此模組使用特殊的字串資料類型,字元編碼應該作為單獨的參數提供。

混合字元編碼 #

為了方便字元編碼之間的轉換,我認為介面應接受不同參數和傳回值的不同編碼。這使得可以即時轉換,並讓函數決定提供的參數和傳回值的最有效字元轉換路徑。

這種方法的缺點是某些函數將採用許多參數來告知不同的字元編碼,例如,字串串連常式可能看起來像

concat(BString1, Encoding1, BString2, Encoding2, Encoding3) -> BString3

像這樣呼叫

US = bstring:concat(SA,latin1, SB, latin1, unicode),

這可能看起來有點尷尬。另一方面,轉換是即時進行的,您無需明確呼叫 unicode 模組來轉換結果。

我認為隱式轉換非常有用,值得為此付出額外的代價。例如,如果沒有隱式轉換,concat 函式幾乎毫無用處,如果禁止轉換,位元語法會更容易使用。

預設字元編碼 #

選擇預設字元編碼並非顯而易見。雖然 ISO-Latin-1 是 Erlang 中的預設值(例如,「“korvsmörgås”」會產生一個 ISO-Latin-1 編碼的二進位字串),但 UTF-8 的使用預計在未來會增長。

儘管選擇 UTF-8 作為預設編碼很誘人,但我認為即使對於這個模組,我們也應該堅持使用 ISO-Latin-1 作為預設值。原因有以下幾點:

  • 我們不需要在添加到標準函式庫的每個模組中都強制執行新的標準。一致性肯定會增加價值,而且位元語法、原始碼編碼以及像 io:format 例程之類的東西都以 ISO-Latin-1 作為預設值。我們不要讓這個模組與其他模組不一致。

  • string 模組通常用於操作任意整數列表,而不總是實際表示文字數據。同樣地,如果使用 ISO-latin-1 版本,bstring 可能可以用來操作任意位元組塊。ISO-Latin-1 實際上是不經解釋的原始位元組,因此任何二進位資料都可以在以 ISO-Latin-1 為導向的例程中處理。使用 UTF-8 編碼作為預設值會將預設函式的使用範圍縮小到僅適用於真正的文字資料。

  • 函式的純 ISO-Latin-1 實作將會是最有效率的,因為根本不需要進行資料檢查。任何位元組值在任何版本中都是可接受的。某些函式即使預期使用 ISO-Latin-1 資料,也可用於 UTF-8 字串。ISO-Latin-1 版本和 UTF-8 版本之間的差異僅在於輸入資料控制。如果給定例如 bstring:concat 的資料已經檢查過是否為正確的 UTF-8,則該函式較簡單的 ISO-Latin-1 版本既更有效率,又能保證給出與輸入一樣正確的輸出。

      CorrectUtf8_1 = give_me_good_string(),
      CorrectUtf8_2 = give_me_another_good_string(),
      CorrectUtf8_3 = bstring:concat(CorrectUtf8_1, latin1, CorrectUtf8_2, latin1, latin1),
      ...
    

    簡而言之,函式的 ISO-Latin-1 版本比純 UTF-8 版本更通用,也更有效率。

  • 可以輕鬆編寫一個提供純 UTF-8 介面的包裝模組。對於 UTF-8 包裝器而言,通過包裝器的開銷將相對較低,而不是 ISO-Latin-1 包裝器,因為模組中 UTF-8 字串的字元解碼/編碼開銷會相當高。簡而言之,與檢查資料是否符合 UTF-8 的成本相比,包裝器的成本非常低。

    我實際上建議使用 ubstring 模組,該模組具有 bstring 介面中暗示預設編碼的部分,但區別在於預期使用 UTF-8。例如,ubstring:tokens/2 函式會像這樣:

      tokens(S,L) -> bstring:tokens(S,unicode,L).
    

    相當簡單。

總之,我認為所有函式都應該存在一個版本,其中沒有提供編碼並且預期使用 ISO-Latin-1 編碼的資料。

語言 #

即使 Unicode 字元可用於表達大多數已知的、現存的和已滅絕的文字,語言和區域知識是完全不同的事情。字串介面通常會強加字串的語言特定屬性,例如從左到右的書寫方向、由空格分隔的字元組成的單詞概念、表示數字和小數點的方式等等。由於 Erlang(尚未)沒有指定字串的此類語言或區域特定屬性的方法,因此介面不應包含與語言相關的功能。string 模組最初不包含此類函式(除了字元對齊函式被命名為 leftright),但不幸的是,已經添加了像 to_floatto_upper 這樣的函式。

我認為在 string 模組中加入與語言相關的函式是一個錯誤,我不想再犯這個錯誤。因此,我沒有在 bstring 中加入此類函式或名稱。

我寧願建議將「Locale」功能作為未來 EEP 的主題。對於那些認為這很簡單的人,請嘗試為所有歐洲語言編寫一個正確的 to_upper 函式,並確保它可以在可以運行 Erlang 的所有平台上工作…也許不是火箭科學,但需要大量的中繼資料。這些資料並不總是在底層作業系統中可用,但可能需要與 Erlang/OTP 一起分發以實現一致的功能。絕對值得單獨提出一個 EEP。

單詞分隔符號 #

在與語言獨立性相關聯的地方,我認為我們應該放棄將單詞視為由空格分隔的字元組的概念。「Token」這個詞更通用,並且沒有以相同的方式表示語言結構。string 模組使用 ASCII 空格字元作為單詞分隔的預設值,我認為應該在 bstring 中刪除它。應該提供任何應該分隔 Token 的符號,可能會以替代方式提供。因此,我建議使用 bstring:num_tokensbstring:nth_token 函式來實現 string:wordsstring:sub_word 的功能。

EEP 9中所示,我建議使用一個新的函式 split 來處理 Token 的多字元分隔符號的情況。splitjoin 的組合也可以方便地建立 replace 函式。

從左到右或從右到左 #

如前所述,我認為不應在介面中暗示圖形表示的方向,因此我建議使用像 leading 和 trailing(表示二進位字串中的前導和尾隨字元)這樣的概念,而不是任何方向性的概念。我也認為對齊字串(如在 strings:right 等中)可以使用一個函式 align 來解決,該函式可以採用原子 leadingtrailingcenter 作為參數(如果應該實作的話)。

命名和重複功能 #

我絕對認為我們不應該將 string 中的所有介面都複製到 bstring 中。尤其是那些別名的介面不應該帶到 bstring 模組中。但是,string 模組中的大多數函式都有簡短且相當描述性的名稱,通常與其他語言中的名稱相似。我認為對於從字串末尾到開頭工作的函式使用 r 字首是個不錯的選擇,而 c 用於補數也是個不錯的選擇。

位元組導向與字元導向的回傳值 #

string 中的某些函式(確實很有用)會回傳表示字元位置的數字。相同的函式肯定應該出現在 bstring 模組中,並且回傳值肯定應該是字元導向的。但是,位元組偏移量絕對有用,例如,如果我們使用像 span 這樣的函式來尋找不在一組字元中的第一個字元,我們可能也想要該第一個字元的位元組偏移量。

我建議添加一些回傳位元組偏移量的介面,或像 binary 模組和 re 中使用的 part(),以應對某些情況下對位元組偏移量和長度的需求。函式名稱的 b 字尾可以表示這種功能,因此 bstring:span 回傳字元位置,而 bstring:spanb 回傳位元組位置,並且 btring:str 回傳字元位置,而 bstring:strb 回傳 part()。雖然這最終會在介面中產生更多函式,但在選項列表中使用回傳類型更改選項並不是一個好方法(我知道,我在 re 中使用了它們,但這仍然不是一個普遍的好主意…)。

新的或取代的功能 #

在編寫通用字串模組時,可以添加或多或少深奧的新功能是沒有止境的。我認為,至少在最初的實作中,我們應該堅持 EEP 9 中概述的功能,即擴展 str 和相關函式,使其可以選擇採用要搜尋的替代字串列表,添加一個 split 函式來處理多字元分隔符號(與 tokens 函式中的單字元分隔符號相對),以及一個替換函式,我認為應該像其他模組一樣命名為 replace

但是,使用 binary 模組中的預先編譯的匹配並不是一個好主意,因為 binary 模組沒有字元編碼的概念。搜尋字串需要以定義的字元編碼給出,並且在執行有效搜尋時需要知道「haystacks」和「needles」的編碼。因此 - 沒有預先編譯的搜尋表達式。

建議的手冊頁摘錄 #

如上所述,我更喜歡使用 bstring 作為二進位字串模組的名稱,而不是最初建議的更冗長的名稱 binary_string。在該 bstring 模組中,我建議使用以下介面,以 OTP 手冊頁的形式表示。

資料類型 #

encoding() = latin1 | unicode | utf8
    - The encoding of characters in the binary data, both input and output
bstring()
    - Binary with characters encoded either in ISO-Latin-1 or UTF-8
unicode_char() = non_negative_integer()
    - An integer representing a valid unicode codepoint
non_negative_integer()
    - An integer >= 0

匯出 #

align(BString, Alignment, Number, Char) -> Result #

align(BString, Encoding, Alignment, Number, Char) -> Result #

類型

BString = Result = bstring()
Encoding = encoding()
Alignment = leading | trailing | center
Number = non_negative_integer()
Char = unicode_char()

根據 Alignment 參數,在具有 Number 個字元的 Result 中對齊 BString 中的字元。對齊的方式是在二進位字串的開頭或結尾(或兩者)插入字元 Char

產生的二進位字串將恰好包含 Number 個字元,如果它包含的字元多於 Number 個字元,則會截斷字串 - 如果 Alignmentleading,則會在結尾截斷;如果 Alignmenttrailing,則會在開頭截斷;如果 Alignmentcenter,則會在兩端截斷。如果 Encodingunicode,則 Result 可能會包含比 Number 更多的位元組,因為一個字元可能需要多個位元組。

範例

> bstring:align(<<"Hello">>, latin1, center, 10, $.).
<<"..Hello...">>

如果未指定編碼,則假設為 latin1,表示不會對二進位字串中的位元組進行任何解釋。

如果 BString 不包含根據 Encoding 參數編碼的字元、EncodingAlignment 具有無效值、字元 Char 無法以給定為 Encoding 的字元編碼進行編碼或任何參數類型錯誤,則會引發 badarg 例外。

chr(BString, Character) -> Position #

chr(BString, Encoding, Character) -> Position #

rchr(BString, Character) -> Position #

rchr(BString, Encoding, Character) -> Position #

類型

BString = bstring()
Encoding = encoding()
Character = unicode_char()
Position = integer()

回傳 BString 中第一個/最後一個出現的 Character 的(從零開始的)字元位置。如果 Character 沒有出現,則回傳 -1

請注意,字元位置與位元組位置不同。使用 chrbrchrb 函式取得位元組位置。

如果 Character 無法在編碼中表示,這不是錯誤,你只是確定會取得 -1 作為回傳值。

如果未指定編碼,則假設為 latin1,表示不會對二進位字串中的位元組進行任何解釋。

如果 BString 的搜尋部分不包含根據 Encoding 參數編碼的字元、Encoding 具有無效值或任何參數類型錯誤,則會引發 badarg 例外。

chrb(BString, Character) -> {BytePosition, ByteLength} #

chrb(BString, Encoding, Character) -> {BytePosition, ByteLength} #

rchrb(BString, Character) -> {BytePosition, ByteLength} #

rchrb(BString, Encoding, Character) -> {BytePosition, ByteLength} #

類型

BString = bstring()
Encoding = encoding()
Character = unicode_char()
BytePosition = integer()
ByteLength = non_negative_integer()

分別與 chrrchr 的工作方式相同,但回傳字元的位元組位置和位元組長度。

如果未找到該字元,則回傳 {-1,0}

concat(BString1, BString2) -> BString3 #

concat(BString1, Encoding1, BString2, Encoding2, Encoding3) -> BString3 #

類型

BString1 = BString2 = BString3 = bstring()
Encoding1 = Encoding2 = Encoding3 = encoding()

將兩個二進制字串連接起來,形成一個新的字串。以 Encoding3 指定的編碼方式返回新的二進制字串。

如果未指定編碼,則假設為 latin1,表示不會對二進位字串中的位元組進行任何解釋。

如果 BString1Bstring2 未包含根據 Encoding1Encoding2 參數編碼的字元、編碼參數具有無效值、輸入參數中的碼位無法以輸出編碼表示,或者任何參數的類型錯誤,則會引發 badarg 異常。

equal(BString1, BString2) -> bool() #

equal(BString1, Encoding1, BString2, Encoding2) -> bool() #

類型

BString1 = BString2 = bstring()
Encoding1 = Encoding2 = encoding()

測試兩個二進制字串是否相等。如果相等,則返回 true,否則返回 false

Encoding1BString1 的編碼,而 Encoding2BString2 的編碼。

請注意,字串可以具有不同的編碼,並且比較的是字串中編碼的字元值。二進制字串會一直掃描到它們相等為止,這表示如果函式返回 true,則兩個字串都經過正確編碼;而返回值 false 並不保證兩個二進制字串都經過正確編碼。如果在比較字串時發現錯誤編碼,則會引發異常,而不是在未檢查的字串部分包含編碼錯誤時引發異常。

如果未指定編碼,則假設為 latin1,表示不會對二進位字串中的位元組進行任何解釋。

如果在比較過程中遇到根據編碼參數錯誤編碼的字元、編碼參數具有無效值,或任何參數的類型錯誤,則會引發 badarg 異常。

join(BStringList, Separator) -> Result #

join(BStringList, BStringListEncoding, Separator, SeparatorEncoding, ResultEncoding) -> Result #

類型

BStringList = [bstring()]
BStringListEncoding = SeparatorEncoding = ResultEncoding = encoding()
Separator = bstring()
Result = bstring()

返回一個二進制字串,其中 BStringList 的元素由 Separator 中的二進制字串分隔。

BStringList 中的所有二進制字串都應具有相同的編碼 (以 BStringListEncoding 給定)。但是,Separator 可以具有不同的編碼 (以 SeparatorEncoding 給定),Result 也可以具有不同的編碼 (以 ResultEncoding 給定)。

範例

> bstring:join([<<"one">>, <<"two">>, <<"three">>], latin1, <<", ">>, latin1, latin1).
<<"one, two, three">>

如果未指定編碼,則假設為 latin1,表示不會對二進位字串中的位元組進行任何解釋。

如果 BStringList 中的二進制字串或 Separator 未包含根據 BStringListEncodingSeparatorEncoding 參數編碼的字元,編碼參數具有無效值,輸入參數中的碼位無法以輸出編碼 ResultEncoding 表示,或者任何參數的類型錯誤,則會引發 badarg 異常。

len(BString) -> Length #

len(BString, Encoding) -> Length #

類型

BString = bstring()
Encoding = encoding()
Length = non_negative_integer()

返回二進制字串中的字元數。

如果未指定編碼,則假設為 latin1,表示不會對二進位字串中的位元組進行任何解釋。

如果 BString 未包含根據 Encoding 參數編碼的字元、Encoding 具有無效值,或任何參數的類型錯誤,則會引發 badarg 異常。

nth_token(BString, N, CharList) -> Result #

nth_token(BString, Encoding, N, CharList) -> Result #

類型

BString = Result = bstring()
Encoding = encoding()
CharList = [ unicode_char() ]
N = non_negative_integer()

返回 BString 的第 N 個 Token (從零開始)。Token 由 CharList 中的字元分隔。

返回的 Token 將具有與 BString 相同的編碼。

例如

> bstring:nth_token(<<" Hello old boy !">>,latin1,3,[$o, $ ]).
<<"ld b">>

CharList 應視為字元的「集合」,順序並不重要。CharList 中給定的,無法由 Encoding 表示的碼位不是錯誤。

如果 N 的值 >= BString 中的 Token 數,將會返回空的二進制字串 <<>>

如果未指定編碼,則假設為 latin1,表示不會對二進位字串中的位元組進行任何解釋。

如果 BString 未包含根據 Encoding 參數編碼的字元、Encoding 具有無效值,或任何參數的類型錯誤,則會引發 badarg 異常。

num_tokens(BString, CharList) -> Count #

num_tokens(BString, Encoding, CharList) -> Count #

類型

BString = bstring()
Encoding = encoding()
CharList = [ unicode_char() ]
Count = non_negative_integer()

返回 String 中的 Token 數,這些 Token 由 CharList 中的字元分隔。

結果與 length(bstring:tokens(BString,Encoding,CharList)) 相同,但避免建立結果。

例如

> num_tokens(<<" Hello old boy!">>, latin1, [$o, $ ]).
4

CharList 應視為字元的「集合」,順序並不重要。CharList 中給定的,無法由 Encoding 表示的碼位不是錯誤。

如果未指定編碼,則假設為 latin1,表示不會對二進位字串中的位元組進行任何解釋。

如果 BString 未包含根據 Encoding 參數編碼的字元、Encoding 具有無效值,或任何參數的類型錯誤,則會引發 badarg 異常。

span(BString, Chars) -> Length #

span(BString, Encoding, Chars) -> Length #

rspan(BString, Chars) -> Length #

rspan(BString, Encoding, Chars) -> Length #

cspan(BString, Chars) -> Length #

cspan(BString, Encoding, Chars) -> Length #

rcspan(BString, Chars) -> Length #

rcspan(BString, Encoding, Chars) -> Length #

類型

BString = bstring()
Encoding = encoding()
Chars = [ integer() ]
Length = non_negative_integer()

返回 BString 的最大初始 (span 和 cspan) 或尾隨 (rspan 和 rcspan) 段的長度 (以字元為單位),這些段完全由 Chars 中的字元 (span 和 rspan) 或非 Chars 中的字元 (cspan 和 rcspan) 組成。

Chars 應視為字元的「集合」,順序並不重要。Char 中給定的,無法由 Encoding 表示的碼位不是錯誤。

例如

> bstring:span(<<"\t    abcdef">>,latin1," \t").
5
> bstring:cspan((<<"\t    abcdef">>,latin1, " \t").
0

Chars 中無法由 Encoding 表示的碼位不視為錯誤。

如果未指定編碼,則假設為 latin1,表示不會對二進位字串中的位元組進行任何解釋。

如果 BString 的搜尋部分不包含根據 Encoding 參數編碼的字元、Encoding 具有無效值或任何參數類型錯誤,則會引發 badarg 例外。

spanb(BString, Chars) -> ByteLength #

spanb(BString, Encoding, Chars) -> ByteLength #

rspanb(BString, Chars) -> ByteLength #

rspanb(BString, Encoding, Chars) -> ByteLength #

cspanb(BString, Chars) -> ByteLength #

cspanb(BString, Encoding, Chars) -> ByteLength #

rcspanb(BString, Chars) -> ByteLength #

rcspanb(BString, Encoding, Chars) -> ByteLength #

類型

BString = bstring()
Encoding = encoding()
Chars = [ integer() ]
ByteLength = non_negative_integer()

功能與 spanrspancspanrcspan 函式完全相同,但返回的是位元組數而不是字元數。

split(BString, Separators, Where) -> Tokens #

split(BString, Encoding, Separators, SepEncoding, Where, ReturnEncoding) -> Tokens #

類型

String = bstring()
Encoding = SepEncoding = ReturnEncoding = encoding()
Separators = [ bstring() ]
Where = first | last | all
Tokens = [bstring()]

返回 BString 中的 Token 清單,這些 Token 由 Separators 中的二進制字串分隔。

返回的 Tokens 根據 ReturnEncoding 進行編碼。

範例

> bstring:split(<<"abc defxxghix jkl">>, latin1, [<<"x">>,<<" ">>],all,latin1).
[<<"abc">>, <<"def">>, <<"ghi">>, <<"jkl">>]

Separators 應視為二進制字串的「集合」,順序並不重要。Separators 中給定的,無法由 Encoding 表示的碼位不是錯誤。

Where 參數指定在任何 Separators 出現的哪個位置分割二進制字串,可以在 first (第一次) 出現、last (最後一次) 出現,或在 all (所有) 出現的位置分割,在 all 情況下,Tokens 可能是任意長的清單。

如果未指定編碼,則假設為 latin1,表示不會對二進位字串中的位元組進行任何解釋。

如果 BStringSeparators 未包含根據 EncodingSepEncoding 參數編碼的字元,結果 Token 無法在 ReturnEncoding 中編碼,Encoding 具有無效值,或任何參數的類型錯誤,則會引發 badarg 異常。

str(BString, SubBStrings) -> Position #

str(BString, Encoding, SubBStrings, SubEnc) -> Position #

rstr(BString, SubBStrings) -> Position #

rstr(BString, Encoding, SubBStrings, SubEnc) -> Position #

類型

BString = bstring()
SubBString = bstring() | [ bstring() ]
Encoding = SubEnc = encoding()
Position = integer()

返回 SubBStrings 中的任何字串在 BString 中第一次/最後一次出現的 (從零開始) 字元位置。如果 SubBString 不存在於 BString 中,則返回 -1

請注意,字元位置與位元組位置不同。使用 strbrstrb 函式取得位元組位置。

BStringSubBStrings 的編碼不必相同,但是 SubBStrings 中的所有字串都需要具有相同的編碼。

如果 SubBString 中的碼位無法以 BString 的編碼表示,這不是錯誤,但始終會導致返回值 -1。

範例

> bstring:str(<<" Hello Hello World World ">>,latin1,<<"Hello World">>,latin1).
7

請注意,如果兩個編碼相同,並且要使用相同的 SubBStrings 執行重複搜尋,則使用原始二進制資料的預先編譯的模式,使用 binary:match/{2,3} 函式效率更高。

如果未指定編碼,則假設為 latin1,表示不會對二進位字串中的位元組進行任何解釋。

如果 BStringSubBString 的搜尋部分未包含根據 EncodingSubEnc 參數編碼的字元、Encoding 具有無效值,或任何參數的類型錯誤,則會引發 badarg 異常。

strb(BString, SubBStrings) -> {BytePosition, ByteLength} #

strb(BString, Encoding, SubBStrings, SubEnc) -> {BytePosition, ByteLength} #

rstrb(BString, SubBStrings) -> {BytePosition, ByteLength} #

rstrb(BString, Encoding, SubBStrings, SubEnc) -> {BytePosition, ByteLength} #

類型

BString = bstring()
SubBString = bstring() | [ bstring() ]
Encoding = SubEnc = encoding()
BytePosition = integer()
ByteLength = non_negative_integer()

功能與 strrstr 分別相同,但返回的是找到的子字串的位元組位置和位元組長度。

請注意,ByteLength 是找到的子字串在 BString 中的長度,與 SubBStrings 中的編碼無關,因此 ByteLength 可能大於或小於 byte_size(SubBString),具體取決於二進制字串的編碼。

如果找不到子字串,則返回 {-1,0}

strip(BString, Which, CharList) -> Result #

strip(BString, Encoding, Which, CharList) -> Result #

類型

BString = Result = bstring()
Encoding = encoding()
Which = leading | trailing | both
CharList = [ unicode_char() ]

從二進制字串 BString 中移除屬於 CharList 所指示集合的前導 (Which = leading)、尾隨 (Which = trailing) 或前導和尾隨 (Which = both) 字元。

這基本上與結合使用 spanb 和/或 rspanb 以及位元語法移除字元相同。

範例

> bstring:strip(<<"...He.llo.....">>, latin1, both, [$.]).
<<"He.llo">>

如果未指定編碼,則假設為 latin1,表示不會對二進位字串中的位元組進行任何解釋。

如果 BString 中掃描的部分未包含根據 Encoding 參數編碼的字元,或者 EncodingWhich 的值無效,或者任何參數的類型錯誤,則會引發 badarg 例外。

replace(BString, Separators, Replacement, Where) -> Result #

replace(BString, Encoding, Separators, SeparatorsEncoding, Replacement, ReplacementEncoding, Where, ResultEncoding) -> Result #

類型

BString = bstring()
Encoding = SeparatorsEncoding = ReplacementEncoding, ResultEncoding = encoding()
Separators = [ bstring() ]
Replacement = bstring()
Where = first | last | all
Result = bstring()

產生與下列程式碼相同的結果:

bstring:join(bstring:split(BString,Encoding,Separators,SeparatorsEncoding,Where,
                           unicode),
             unicode,Replacement,ReplacementEncoding,ResultEncoding)

但開銷較少。

substr(BString, Start, Length) -> SubBString #

substr(BString, Encoding, Start, Length) -> SubBString #

類型

BString = SubBString = bstring()
Encoding = bstring()
Start = integer()
Length = non_negative_integer() | infinity

傳回 String 的子字串,從零基底字元位置 Start 開始,並在二進制字串的結尾結束(如果 Lengthinfinity)或直到但不包括字元位置 Start+Length(如果 Length 是非負整數)。

傳回的 SubBString 將具有與 BString 相同的編碼。

範例

> bstring:substr(<<"Hello World">>, latin1, 3, 5).
<<"lo Wo">>

Start 的負值表示從 BString結尾算起 abs(Start) 個字元,因此 -1 是二進制字串中的最後一個字元位置。

範例

> bstring:substr(<<"Hello World">>, latin1, -1, 3).
<<"rld">>

由於確定 UTF-8 編碼二進制字串的真實長度相當耗費資源(O(N),其中 N 是二進制字串中的位元組數),因此該函數對於在字串外部給定的位置(包括 StartLength)非常寬容。在任一方向上超出字串的字元位置都會被折疊為空的二進制字串。

範例

> bstring:substr(<<"01234">>, latin1, 5, 5).
<<>>
> bstring:substr(<<"01234">>, latin1, 4, 5).
<<"4">>
> bstring:substr(<<"01234">>, latin1, -5, 100).
<<"01234">>
> bstring:substr(<<"01234">>, latin1, -6, 1).
<<>>
> bstring:substr(<<"01234">>, latin1, -6, 2).
<<"0">>

如果未指定編碼,則假設為 latin1,表示不會對二進位字串中的位元組進行任何解釋。

如果未指定編碼,則假設為 latin1,表示不會對二進位字串中的位元組進行任何解釋。

如果 BString 的搜尋部分不包含根據 Encoding 參數編碼的字元、Encoding 具有無效值或任何參數類型錯誤,則會引發 badarg 例外。

tokens(BString, SeparatorList) -> Tokens #

tokens(BString, Encoding, SeparatorList) -> Tokens #

類型

String = bstring()
Encoding = encoding
SeparatorList = [ non_negative_integer() ]
Tokens = [bstring()]

傳回 BString 中由 SeparatorList 中的字元分隔的 Token 列表。

傳回的 Tokens 以與 BString 相同的字元編碼進行編碼。

範例

> bstring:tokens(<<"abc defxxghix jkl">>, latin1, [$x,$ ]).
[<<"abc">>, <<"def">>, <<"ghi">>, <<"jkl">>]

SeparatorList 應被視為一組字元,順序並不重要。在 SeparatorList 中給出的,無法由 Encoding 表示的代碼點,並不是錯誤。

如果未指定編碼,則假設為 latin1,表示不會對二進位字串中的位元組進行任何解釋。

如果 BString 的搜尋部分不包含根據 Encoding 參數編碼的字元、Encoding 具有無效值或任何參數類型錯誤,則會引發 badarg 例外。

效能 #

此模組可以,並且可能應該完全在 Erlang 中實現,不需要 BIF 或 NIF。binaryunicode 模組都可以用於加速轉換和輸入數據檢查。Unicode 版本肯定會比 ISO-Latin-1 版本慢,因為字元編碼、解碼和檢查必定會產生開銷。

建議的包裝函式 ubstring 不應比使用所有編碼引數設定為 unicode 的方式呼叫 bstring 產生顯著的成本。

其想法是使使用二進制字串操作變得方便,因為它對系統內存在很大的正面影響。與以列表為導向的字串相比,提高速度並不是目標,儘管它很可能是一個副作用。

參考實作 #

沒有提供特定的參考實作,但在任何開發期間,程式碼將在 GitHub 上提供。

版權 #

本文檔根據 創用CC姓名標示 3.0 授權條款 授權。