在Powershell 7中使用enwik9(UTF-8多字节字符的子字符串)
我正在使用Powershell 7处理Wikipedia enwik9 1Gb UTF-8文本文件。我没有使用Unicode\UTF-8的经验。我已经将偏移量和值捕获到一个dict中,当我使用下面的代码和增量$I++时,它们看起来是成对的2、4和6在Powershell 7中使用enwik9(UTF-8多字节字符的子字符串),utf-8,substring,multibyte,powershell-7.0,Utf 8,Substring,Multibyte,Powershell 7.0,我正在使用Powershell 7处理Wikipedia enwik9 1Gb UTF-8文本文件。我没有使用Unicode\UTF-8的经验。我已经将偏移量和值捕获到一个dict中,当我使用下面的代码和增量$I++时,它们看起来是成对的2、4和6 $line.Length对此字符串有效吗 $i是一个多字节字符,当它移动到下一个迭代时,它仍然有效吗 我怎么知道这个代码包含多少“字符”?它是子字符串($i,1)还是子字符串($i,2)或者子字符串($i,6) 我能够回答自己的问题,并根据本页上的信
我能够回答自己的问题,并根据本页上的信息找到有效的解决方案:
[int][char]:MaxValue
给出65535
(即0xFFFF
)以便1<代码>[byte][char]$s可能会失败,因为[byte]::MaxValue
是255
(即0xFF
),并且2<代码>$line。子字符串($i,1)可以是Unicode BMP以上字符的替代项…来自子字符串的答案会自动正常工作。我必须通过剥离控制位来处理第一个Unicode,读取以下子字符串字符的正确#并重置这些控制位,将2个二进制数组合成一个字符串,转换为十六进制,然后使用$uni='\u'+$hex转换为Unicode$uc=[regex]::Unescape($uni)
@johnj01201,将来,请每个帖子只问一个问题,而不是3个问题。;-)这适用于2字节序列,但我正在处理的文件具有更长的Unicode序列。例如,我得到0xE282AC,它抛出一个超出范围的错误。我在这里找到的:它是欧元的象征。我还没有找到在Powershell中使用Internet上的任何示例和函数来显示此Unicode字符的方法。我通过将十六进制粘贴到在线十六进制到Unicode转换器中确认了十六进制是有效的:由于对UTF-8和Unicode还不熟悉,我想我正在尝试Powershell已经自动完成的工作。不断发生的问题是[char]有时有3个字节长,我无法使用它。例如,子字符串($line,$i,1)的长度可以是3字节,而不是1!!!最后,解决方案是更改文件的加载方式。现在,子字符串可以正确地用于每个Unicode字符$text=(获取内容'enwik9.txt'-Raw)更改为$text=(获取内容'enwik9.txt'-Raw-编码UTF8)现在,所有符号都正确显示,长度为1[char]。
$text = (Get-Content 'enwik9.txt' -Raw)
$line = $text.Substring($i, 10000000)
for ($i = 0; $i -lt $line.Length; $i++) {
$total_cnt++
$s = $line.Substring($i, 1)
$n = [int][CHAR]$s #I wanted [byte][char] here
if ($n -ge 128) {
# Now $n is not what I want because it is not ASCII and > 255 a Unicode\multibyte character
}
}
clear-host
clear
write-host 'Loading enwik9.txt'
$text = (Get-Content 'enwik9.txt' -Raw)
write-host 'Load Complete - processing...'
$line = $text.Substring($i,10000000)
for($i=0;$i -lt $line.Length; $i++)
{
$total_cnt++
$uni=''
$s=$line.Substring($i,1)
$n=[int][CHAR]$s
if($n -ge 128)
{
# how many byte units in this Unicode?
$ns=0
$bin=0
$n=$n-128 #reset the 8th contol bit
$b7 = $n -band 64; if($b7 -eq 64){$ns=1;$n=$n-64} #remove the contorl bits
$b6 = $n -band 32; if($b6 -eq 32){$ns-2;$n=$n-32}
$b5 = $n -band 16; if($b5 -eq 16){$ns=3;$n=$n-16}
$t=[convert]::ToString($n,16).PadLeft(2,'0') #convert int to hex
$bin= [convert]::tostring($n,2)
write-host 'Found a Unicode start byte $ns='$ns ' $n='$n
for($c=1;$c -le $ns; $c++)
{
$i++; $total_cnt++; #remember to increment the main loop index into #line
$s=$line.Substring($i,1) #read the next string char
$n=[int][CHAR]$s #convert to int
if($c -eq 1)
{
if( (($n -band 128) -eq 128) -and (($n -band 64) -ne 0) )
{
write-host 'NOT A CONTINUE BIT $ns='$ns
}
$n=$n-128 #reset the 8th bit
$b7 = $n -band 64; if($b7 -eq 64){$n=$n-64} #remove the contorl bits
}
$t=[convert]::ToString($n,16).PadLeft(2,'0') #convert int to hex
$bin=$bin+ [convert]::tostring($n,2)
$number = [Convert]::ToInt32($bin, 2) #conver to int
$hex = [convert]::ToString($number,16).PadLeft(4,'0')
write-host '$s='$s ' $n='$n ' $t='$t ' $bin='$bin ' $hex='$hex
}
$uc=''
if($ns -eq 0){write-host 'SINGLE BYTE'; Read-Host 'ENTER';}
ELSE{ $uni='\u'+$hex; $uc = [regex]::Unescape($uni) }
write-host 'FINAL: Unicode is: '$uc
read-host "press ENTER to find and process next unicode character"
}
}