注意:
- 不需要使用
[regex] :: Unescape()
,因为JSON的转义与正则表达式的转义无关。
- 也就是说,
$fileContent | ConvertFrom-Json | ConvertTo-Json
应该可以直接工作,但是由于
Windows PowerShell中的一个怪异问题,导致输入字符串中的
&
被表示为其等效的
转义序列,即
\u0026
,重新转换时产生问题;类似地,
'
(
\u0027
),
<
(
\u003c
)和
>
(
\u003e
)也会受到影响。
简而言之:
问题不影响PowerShell(Core)6+(按需安装、跨平台PowerShell版本),它使用不同的实现
ConvertTo-Json
和
ConvertFrom-Json
cmdlet,最新版本为PowerShell 7.2.x,基于
Newtonsoft.JSON(在
r3verse的答案中展示了其
直接用法)。在那里,您的示例往返命令按预期工作。
只有
Windows PowerShell中的ConvertTo-Json
受到影响(附带了Windows的PowerShell版本,最新且最终版本为5.1)。但请注意,
JSON表示法-虽然出乎意料-但在技术上是正确的
。
一个
简单但强大的解决方案仅专注于取消转义那些
ConvertTo-Json
意外创建的Unicode转义序列-即
& ' < >
,同时排除错误的情况:
$json = '"Ten o\u0027clock at \u003cnight\u003e \u0026 later. \\u0027 \\\\u0027"'
[regex]::replace(
$json,
'(?<=(?:^|[^\\])(?:\\\\)*)\\u(00(?:26|27|3c|3e))',
{ param($match) [char] [int] ('0x' + $match.Groups[1].Value) },
'IgnoreCase'
)
以上代码输出所需的JSON表示形式,而不需要对&
、'
、<
和>
进行不必要的转义,并且不会错误地替换转义子字符串\\u0027
和\\\\u0027
:
"Ten o'clock at <night> & later. \\u0027 \\\\u0027"
背景信息:
Windows PowerShell
中的ConvertTo-Json
在JSON字符串中意外地用它们的Unicode转义序列来表示以下ASCII范围字符:
&
(Unicode转义序列: \u0026
)
'
(\u0027
)
<
和 >
(\u003c
和 \u003e
)
没有必要这样做 (这些字符只需要在HTML/XML文本中进行转义)。
然而,任何符合规范的JSON解析器 - 包括 ConvertFrom-Json
- 都会将这些转义序列转换回它们所代表的字符。
换句话说:虽然由Windows PowerShell的ConvertTo-Json
创建的JSON文本是意外的并且可能影响可读性,但从技术上讲,它是正确的,并且 - 虽然不是完全相同 - 在表示数据方面与原始表示等效。
解决可读性问题:
顺带一提: 虽然[regex]::Unescape()
的目的是只对正则表达式进行反转义,但它还将Unicode转义序列转换为它们所代表的字符,但它基本上不适用于有选择性地取消JSON字符串中的Unicode序列转义,因为所有其他\
转义必须被保留以使JSON字符串保持语法上有效。
虽然你的答案在一般情况下都有效,但它有局限性(除了可以轻松纠正的问题之外,即a-zA-Z
应该是a-fA-F
,以限制匹配到那些有效的十六进制数字字母):
要想得到一个 健壮的解决方案 来克服这些限制,请参见此答案
(代理项序列保留为Unicode转义序列,需要转义的字符对应的Unicode转义序列会被转换为基于\
的(C风格)转义字符,例如\n
, 如果可能)。
然而,如果唯一要求是反转Windows PowerShell的ConvertTo-Json
意外创建的Unicode转义序列,则顶部的解决方案是足够的。
*-CliXml
cmdlet)。 - Maximilian Burszley