首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Powershell - ASCII编码正在将特殊字符更改为问号

Powershell - ASCII编码正在将特殊字符更改为问号
EN

Stack Overflow用户
提问于 2017-10-28 01:14:12
回答 2查看 10.5K关注 0票数 3

我使用如下的Powershell脚本将字符串转换为XML,然后导出到文件中(这样做是为了保持缩进):

代码语言:javascript
复制
[xml]$xmloutput = $xml
$sw = New-Object System.IO.StringWriter
$writer = New-Object System.Xml.XmlTextWriter($sw)
$writer.Formatting = [System.Xml.Formatting]::Indented
$xmloutput.WriteContentTo($writer)
$sw.ToString() | Set-Content -Encoding 'ASCII' $filepath

由于供应商的限制,目标必须采用ASCII格式。我所看到的问题是ASCII只是将特殊字符转换为问号(例如:?变为?)。

如果我使用UTF8编码,输出看起来完全没问题。我甚至尝试过保存为UTF8,然后转换为ASCII码,做同样的事情(导出一个问号):

代码语言:javascript
复制
[System.Io.File]::ReadAllText($filepath) | Out-File -FilePath $filepath -Encoding ASCII

如果我尝试在转换成XML之前替换字符串中的字符(使用ASCII码Ö),它只是转换“与”号,剩下的就没有用了。

有没有办法让Powershell正确地将这些字符保存到文件中?

编辑:我希望看到输出文件中的特殊字符,但如果这不符合ASCII码,我希望看到它的ASCII码(在本例中为Ö)。

我也不想只看到一个O,我需要实际的字符。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-10-28 04:20:58

XML文档中的所有字符都是Unicode。但是,XML文档的表示具有文档编码。不属于该字符集的字符被写为字符实体引用,通常以数字和十六进制表示法编写。该数字是Unicode代码点。

看起来你的合作伙伴的要求是使用ASCII作为文档编码。

使用XmlDocument有点困难,但带有文档编码设置的XmlWriter可以工作:

代码语言:javascript
复制
$myString = 'hellÖ'

[xml]$myXml = [System.Management.Automation.PSSerializer]::Serialize($myString)

$settings = New-Object System.Xml.XmlWriterSettings
$settings.Encoding = [System.Text.Encoding]::ASCII
$settings.Indent = $true

$writer = [System.Xml.XmlWriter]::Create("./test.xml", $settings)
$myXml.Save($writer)
$writer.Dispose()

这将输出一个ASCII编码的文本文件,并使用XML解码声明文档编码为ASCII,并对不能用ASCII表示的XML内容字符使用十六进制数字字符实体引用:

代码语言:javascript
复制
<?xml version="1.0" encoding="us-ascii"?>
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
  <S>hell&#xD6;</S>
</Objs>

正如您在C1控制和拉丁文-1补充模块中看到的here,U+00D6 (&#D6;)是带分音符的?拉丁文大写字母O

票数 6
EN

Stack Overflow用户

发布于 2017-10-28 02:14:01

这并不是PowerShell所特有的,这通常是一个字符编码问题。

基本上,该字符不是ASCII,而是ISO 8859-1。

而且,通过让XmlTextWriter直接写入文件,可以简化这个过程,因为您可以用它来控制编码。试试这个:

代码语言:javascript
复制
$myString = 'hellÖ'

[xml]$myXml = [System.Management.Automation.PSSerializer]::Serialize($myString)

$myEncoding = [System.Text.Encoding]::GetEncoding('iso-8859-1')

$writer = New-Object System.Xml.XmlTextWriter($filepath, $myEncoding)
$writer.Formatting = [System.Xml.Formatting]::Indented

$myXml.WriteContentTo($writer)

$writer.Flush()
$writer.Close()
$writer.Dispose()

这将使用ISO 8859-1编码写入文件,但不会将其编码为XML实体。

因此,如果您的应用程序只需要真正的ASCII,没有扩展集,那么这将不起作用。如果它真的只需要单字节编码,并且这种编码中的字符集就足够了,那么就可以了。

如何对实体执行此操作:

第1步:忽略我写的内容,改用

您可以做的是在ASCII编码器上设置一个custom fallback callback,这样每当它遇到一个无法用ASCII表示的字符时,它就会调用您的函数来获取一个替换字符。您的函数只需返回字符的实体版本即可。

从技术上讲..这可能会适得其反。由于您必须从编码器返回与号&,XmlWriter可能会看到这一点,并“有帮助地”将其替换为&amp;,这将破坏您的编码。

直接从PowerShell使用这个回调可能是可能的,但会有点麻烦。使用一些C#和Add-Type会更容易一些。

或者,您可以使用此方法的游击版:编写XML字符串,然后手动替换任何非ASCII的字符。

在这里,我使用的是regex引擎的replace方法的一个版本,该方法接受一个用于匹配计算的函数。正则表达式只匹配不在'BasicLatin‘Unicode Named Block中的任何字符。

代码语言:javascript
复制
$myString = 'hellÖ'

[xml]$myXml = [System.Management.Automation.PSSerializer]::Serialize($myString)

$sw = New-Object System.IO.StringWriter
$writer = New-Object System.Xml.XmlTextWriter($sw)
$writer.Formatting = [System.Xml.Formatting]::Indented
$myXml.WriteContentTo($writer)

$output = [RegEx]::Replace($sw.ToString(), '\P{IsBasicLatin}', { param($match) '&#{0};' -f [int][char]$match.Value })
$output  | Set-Content -Encoding 'ASCII' -LiteralPath $filepath

据我所知,这将会做你想要的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46980317

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档