В Windows PowerShell кодировка символов по умолчанию при чтении из / записи в файлах - это «ANSI» , то есть устаревшая 8-битная кодовая страница, подразумеваемая языком активной системы .
(Напротив, PowerShell Core по умолчанию использует UTF-8.)
Например, кодовая страница, связанная с системным языком в системе на английском и американском языках, равна 1252
, т. Е. Windows-1252 , где кодовая точка 0x93
является не-ASCII “
кавычка.
Но как только содержимое текстового файла будет считано в память, в памяти символы строки представляются в виде UTF-16LE кодовых единиц , т. Е. как .NET [string]
экземпляры.
Как символ Unicode , “
имеет кодовую точку U+201c
, выраженную как 0x201c
в UTF-16LE.
Следовательно - поскольку в памяти все строки являются кодовыми единицами UTF-16LE, необходимо заменить на [char] 0x201c
:
$q1 = [char] 0x201c # “
Get-ChildItem *.csv -Recurse | ForEach-Object {
(Get-Content $_.FullName) -replace $q1, '""' | Set-Content $_.FullName
}
Обратите внимание, что Set-Content
также использует кодировку символов по умолчанию, поэтому переписанные файлы также будут использовать кодировку "ANSI" - используйте параметр -Encoding
для изменения выходной кодировки, если это необходимо.
Также обратите внимание на (...)
вокруг вызова Get-Content
, который гарантирует, что входной файл, который я прочитал в память полностью вперед, что позволяет записывать обратно в тот же файл в том же конвейере.
Хотя этот подход удобен, имейте в виду, что он несет небольшой риск потери данных, если запись во входной файл прерывается до завершения.
Преобразование кодовой точки ANSI в кодовую точку Unicode
Ниже показано, как можно преобразовать 8-битную кодовую точку ANSI, такую как 0x93
, в эквивалентную кодовую точку UTF-16, 0x201c
:
# Convert an array of "ANSI" code points (1 byte each) to the UTF-16
# string they represent.
# Note: In Windows PowerShell, [Text.Encoding]::Default contains
# the "ANSI" encoding set by the system locale.
$str = [Text.Encoding]::Default.GetString([byte[]] 0x93) # -> '“'
# Get the UTF-16 code points of the characters making up the string.
$codePoints = [int[]] [char[]] $str
# Format the first and only code point as a hex. number.
'0x{0:x}' -f $codePoints[0] # -> '0x201c'