working with enwik9 in Powershell 7 (substring from UTF-8 multibyte chars)

180 Views Asked by At

I'm using Powershell 7 to work with the Wikipedia enwik9 1Gb UTF-8 text file. I have no experience with Unicode\UTF-8. I've captured the offset and values into a dict and they seem to come in pairs of 2,4, and 6 together when I use the code below and increment $i++.

  1. Is $line.Length valid for this string?
  2. $i is at a multibyte char, when it moves to the next iteration is it still valid?
  3. How do I know how many "chars" this one code contains? Is it Substring($i,1) or Substring($i,2) or maybe Substring($i,6)?
$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
    }
}
 
1

There are 1 best solutions below

2
On

I was able to answer my own questions and find a working solution based on the information on this page: Ã © and other codes

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"
  }
}