仅使用.NET GetBytes方法转换有效字节而不创建问号

ni65a41a  于 2022-12-14  发布在  .NET
关注(0)|答案(1)|浏览(122)

我正在将带有奇怪符号的字符串转换成Latin-1(或者至少是微软的做法),然后再转换回字符串。我使用PowerShell,但这只是关于.NET方法的:

$bytes = [System.Text.Encoding]::GetEncoding(1252).GetBytes($String)
    $String = [System.Text.Encoding]::GetEncoding(1252).GetString($bytes)

这个方法很奇怪,只是奇怪的符号没有被删除,而是创建了问号,例如:
“你好?→”
变成
“你好????”
我想要的是只转换有效字节,而不创建问号,因此输出将是:
“喂?”
这可能吗?我已经搜索了一下,但是什么都没有找到。ChatGPT骗我说会有一个“GetValidBytes”方法,但是没有...

3ks5zfa0

3ks5zfa01#

一个选项是使用基于 *named Unicode块a的regex-based -replace操作:

"Helloäöü€?→" -creplace '[^\p{IsBasicLatin}\p{IsLatin-1Supplement}–—€‚‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•˜™š›œžŸ]'

假设您的输入已经是一个.NET字符串(因此由UTF-16代码单元组成),那么就没有必要进行字节之间的转换:

  • \p{IsBasicLatin}\p{IsLatin-1Supplement匹配ISO-8859-1 Unicode * 子范围 * 中的字符,该子范围 * 大部分 * 与Windows-1252相同,但缺少一些字符。
  • 显式枚举的字符(€...)是那些在ISO-8859-1中 * 不 * 存在的Windows-1252字符(因此在Unicode中与Windows-1252中具有不同的码位,即在8位范围之外)。
  • (短破折号和长破折号)放在 first,这样它们就不会被误认为描述了一个 range 字符(.NET regex引擎显然允许它们与-互换使用,-是常规的“破折号”(ASCII范围连字符)。
  • (单低9引号)是 * 双 * 的,以便 * 转义 * 它,因为PowerShell允许它与'(单引号)互换使用-另请参阅:this answer总结了PowerShell中允许的所有此类可互换使用。

通过将所有 * 非 * 匹配(^)字符替换为(隐含的)* 空字符串 *,所有非Windows-1252字符都将被有效地删除。
一般警告:

  • 由于在命令中使用了 literal 非ASCII范围字符,请确保PowerShell正确解释脚本文件的字符编码,这意味着使用UTF-8文件 * 和BOM*,以获得 Windows PowerShell 的好处-请参阅this answer

然而,您的to-and-from-bytes编码方法 * 可以 * 稍加修改后使用,适用于 * 任何 * 目标编码(无需枚举单个字符,如上文所述):
使用以 empty string 初始化的System.Text.EncoderReplacementFallback示例可以有效地删除所有无法在目标编码中表示的字符。

$string = "Helloäöü€?→"

$encoding = [System.Text.Encoding]::GetEncoding(
  1252,
  # Replace non-Windows-1252 chars. with '' (empty string), i.e. *remove* them.
  [System.Text.EncoderReplacementFallback]::new(''),
  [System.Text.DecoderFallback]::ExceptionFallback # not relevant here
)

$string = $encoding.GetString($encoding.GetBytes($string))

相关问题