在我的一個Perl腳本中,我必須將UTf-8和原始位元組混合寫入檔案中。
我有一個大字串,其中的所有內容都被編碼為UTF-8。在這個 "源 "字串中,UTF-8字符就像它們應該是的那樣(也就是UTF-8有效的位元組序列),而 "原始位元組 "則被存盤為原始位元組所持有的值的代碼點。因此,在源字串中,一個0x50的 "原始 "位元組將被存盤為一個0x50的位元組;而一個0xff的 "原始 "位元組將被存盤為一個0xc3 0xbf的兩位元組UTF-8有效序列。當我寫回這些 "原始 "位元組時,我需要將它們放回單位元組形式。
我有其他資料結構,允許我知道字串的哪些部分代表什么樣的資料。一個欄位、型別、長度等的串列。
當在普通檔案中寫入時,我依次寫入每個欄位,要么直接寫入(如果它是UTF-8),要么通過將其值編碼為ISO-8859-1,如果它是要成為原始位元組。它作業得非常好。
現在,在某些情況下,我需要將該值不是直接寫入檔案,而是作為 BerkeleyDB(Btree,但這主要是不相關的)資料庫的記錄。 要做到這一點,我需要在一次寫操作中寫下構成我的記錄的所有值。這意味著我需要有一個標量來保存UTF-8和原始位元組的混合資料。
示例:
輸入標量(所有十六進制值):61 C3 8B 00 C3 BF
預期的輸出格式。2個UTF-8字符,然后2個原始位元組。
預期輸出:2個UTF-8字符,然后2個原始位元組。
預期輸出。61 C3 8B 00 FF
一開始,我創建了一個新的檔案。
起初,我通過連接我從一個空字串寫到我的檔案中的相同值來創建一個字串。我試著把這個字串寫到一個 "標準 "檔案中,而沒有添加編碼。我得到了'?'字符,而不是所有超過0x7f的原始位元組(因為,很明顯,Perl決定認為我的字串是UTF-8)。
然后,為了試圖告訴Perl它已經被編碼了,并且 "請不要自作聰明",我試圖將UTF-8部分編碼為 "UTF-8",將二進制部分編碼為 "ISO-8859-1",并將所有內容連接起來。然后我就寫了。這一次,位元組看起來很完美,但已經是UTF-8的部分被 "雙重編碼 "了,也就是說,一個多位元組字符的每個位元組都被看作是它的編碼點......
。
我以為Perl不應該把 "內部 "的UTF-8重新編碼為 "已編碼 "的UTF-8,如果它內部被標記為UTF-8的話。保存所有 UTF-8 值的字串來自 C API,它設定了 UTF-8 標記(或者至少應該設定),以讓 Perl 知道它已經被解碼了。
你知道我在那里錯過了什么嗎?
有沒有一種方法可以告訴 Perl 我想做的事情就是把一堆位元組一個接一個地放進去,并且請不要試圖以任何方式解釋它們? 我寫的檔案是以">:raw "的形式打開的,原因就在于此,但我想我也需要一種方法來指定某個標量是 "raw "的。
后記。我找到了問題的原因。$bigInputString 應該完全由UTF-8編碼的資料組成。但是它確實包含有大值的原始位元組,因為C語言的一個錯誤(原來 "char"(不是 "unsigned char")最好用位運算子來測驗,而不是"> 127"...咳咳)。所以,"大 "位元組沒有被分割成兩個位元組的UTF-8序列,在C API中。
這意味著從糟糕的 C 資料中創建的 $bigInputString 沒有預期的內容,而且 Perl 也不喜歡它。
在我糾正了這個錯誤之后,這個字串被正確地編碼為 UTF-8(對于我想保留為 UTF-8 的部分)或 LATIN-1(對于我想轉換回來的 "原始位元組"),并且我沒有得到進一步的問題。
很抱歉,浪費了你們的時間,伙計們。但我還是學到了一些東西,所以我會把它放在這里。這個故事的寓意是,Devel::Peek對于除錯來說是很好的(感謝ikegami),而且人們應該總是仔細檢查,而不是假設。當然,我在周五的時候很匆忙,但錯還是在我。
因此,感謝每一個幫助過或試圖幫助過我的人,并特別感謝ikegami(再次),他用了很多時間幫助我。
uj5u.com熱心網友回復:
假設你有一個Unicode字串,你知道每個代碼點應該被存盤為什么--一個UTF-8序列或一個單位元組,并且有辦法創建一個模板字串,其中每個字符代表unicode字串中相應的一個應該使用的字符(U用于UTF-8,C用于單位元組以保持簡單),你可以使用pack:
#!/usr/bin/env perl
use strict;
使用警告。
sub process{
my ($str, $formats) = @_;
my $template = "C0$formats"/span>;
my @chars = map { ord } split(//, $str);
pack $template, @chars;
}
my $str = "x61xC3x8Bx00xC3xBF"/span>;
utf8::decode($str);
print process($str, "UUCC"); # outputs 0x61 0xc3 0x8b 0x00 0xff
uj5u.com熱心網友回復:
所以你有
my $in = "x61xC3x8Bx00xC3xBF"/span>。
而且你要
my $out = "x61xC3x8Bx00xFF"。
這是只對輸入字串的某些部分進行解碼的結果,所以你希望得到如下結果:
這是只對輸入字串的某些部分進行解碼的結果。
sub decode_utf8 { my ($s)= @_; utf8: :decode($s) or die("Invalid Input"/span>); $s }
my $out = join "" ,
substr($in, 0, 3)。
decode_utf8(substr($in, 3, 1)。
decode_utf8(substr($in, 4, 2) )。)
測驗.
。另外,你可以對整個東西進行解碼,并對應該編碼的部分進行重新編碼。
sub encode_utf8 { my ($s)= @_; utf8: :encode($s); $s }
utf8::decode($in) or die("Invalid Input"/span>)。
my $out = join "",
encode_utf8(substr($in, 0, 2))。
substr($in, 2, 1)。
substr($in, 3, 1)。
測驗.
。你沒有說明你是如何知道哪些要解碼,哪些不要解碼的,但你表示你有這個資訊。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/328595.html
標籤:
上一篇:GoogleCloudRun中@response.call_on_close的問題
下一篇:為什么我不能列印文本"$!"?
