如何在PowerShell字符串文字中编码Unicode字符代码?

73

我该如何在PowerShell字符串中编码Unicode字符U+0048(H)?

在C#中,我只需执行以下操作:"\u0048",但这似乎在PowerShell中不起作用。


你的输出编码设置是什么?($OutputEncoding) - Joe Chung
1
它是US-ASCII编码。但U+0048应该可以在其中编码。我实际上正在尝试编码一个转义字符(U+001B)。 - dan-gph
7个回答

96

将 '\u' 替换为 '0x' 并将其转换为 System.Char 类型:

PS > [char]0x0048
H

你也可以使用"$()"语法将Unicode字符嵌入到字符串中:
PS > "Acme$([char]0x2122) Company"
AcmeT Company

T 是 PowerShell 表示非注册商标符号的字符。

注意:此方法仅适用于平面0(BMP,基本多语言平面)中的字符,即 Unicode 编码小于 U+10000 的字符。


4
你甚至可以编写一个小函数:function C($n) {[char][int]"0x$n"},在字符串中使用如下:"$(C 48)ello World.",虽不理想但可能更接近 \u 转义符。 - Joey
这也适用于当您想将Unicode [char]传递给函数时。感谢您的帮助。 - Sonamor
1
我知道这个话题已经有2.5年的历史了,但是回应@Joey的评论,你甚至可以创建一个名为\u的函数。它与Joey的函数完全相同,只是名称不同。因此,该函数为function \u($n) {[char][int]"0x$n"}。调用它的方式与C#类似,只是需要在函数名和数字之间加上一个空格。所以\u 0048返回H - chris
这仅适用于BMP中的字符,否则会触发错误。 例如:[char]0x1D400InvalidArgument: 无法将值“119808”转换为类型“System.Char”。错误:“值对于字符来说太大或太小。” - noraj
1
@noraj 这个只适用于BMP字符的原因是因为.NET的char类型表示UTF-16代码单元,对于BMP字符,1个字符=1个代码单元,但对于非BMP字符,1个字符=2个代码单元。/// @chris \u函数可以扩展以适用于非BMP字符。 - undefined

30

17

也许这不是PowerShell的方式,但这就是我所做的。我发现这样更加简洁。

[regex]::Unescape("\u0048") # Prints H
[regex]::Unescape("\u0048ello") # Prints Hello

5

对于我们仍在使用5.1版本并且想要使用高阶Unicode字符集(这些答案都不适用)的人,我创建了此函数,因此您可以简单地构建字符串,如下所示:

'this is my favourite park ',0x1F3DE,'. It is pretty sweet ',0x1F60A | Unicode

enter image description here

#takes in a stream of strings and integers,
#where integers are unicode codepoints,
#and concatenates these into valid UTF16
Function Unicode {
    Begin {
        $output=[System.Text.StringBuilder]::new()
    }
    Process {
        $output.Append($(
            if ($_ -is [int]) { [char]::ConvertFromUtf32($_) }
            else { [string]$_ }
        )) | Out-Null
    }
    End { $output.ToString() }
}

请注意,在控制台中显示这些内容是一个完全不同的问题,但如果你输出到Outlook邮件或Gridview(如下所示),它将正常工作(因为utf16是.NET接口的本地格式)。

enter image description here

这意味着如果你更喜欢使用十进制,你也可以很容易地输出纯控制(不一定是Unicode)字符,因为你实际上不需要使用0x(十六进制)语法来生成整数。 'hello',32,'there' | Unicode 会在两个单词之间放置一个不间断空格,就像你使用0x20一样。

1
"[char]::ConvertFromUtf32"自.NET 2.1以来就可用,因此您不需要使用如此复杂的函数。 - phuclv
哦,很好。这个函数仍然是必要的,我不想每次想要一个 "\u{}" 就写 [char]blahblahblah,但它确实简化了 if 语句。 - Hashbrown
除了使用 $_ -shr 11 替代 [int][math]::Floor($_ / 0x400),还应该使用 ($_ -band 0x3FF) -bor 0xDC00 替代 [char]($_ % 0x400 + 0xDC00) - phuclv
我想这很明显,因为它是一个漂亮的偶数十六进制数字,哦好吧。不过没关系了,现在.NET可以处理这个全局问题。 - Hashbrown

4

如果要使得字符超出BMP范围,你需要使用Char.ConvertFromUtf32()

'this is my favourite park ' + [char]::ConvertFromUtf32(0x1F3DE) + 
'. It is pretty sweet ' + [char]::ConvertFromUtf32(0x1F60A)

4

另一种方法是使用PowerShell。

$Heart = $([char]0x2665)
$Diamond = $([char]0x2666)
$Club = $([char]0x2663)
$Spade = $([char]0x2660)
Write-Host $Heart -BackgroundColor Yellow -ForegroundColor Magenta

使用命令help Write-Host -Full来详细了解它。


1
Shay Levy在上面的回答中已经展示了如何使用[char]0x2665。实际上,这种方法效率更低,因为你需要为每个变量创建一个新的子shell而不是直接赋值:$Heart = [char]0x2665 - phuclv

0
请注意,一些字符(例如)可能需要使用“双符文”才能打印出来:
   PS> "C:\foo\bar\$([char]0xd83c)$([char]0xdf0e)something.txt"

会打印:

   C:\foo\bar\something.txt

你可以在“unicode转义”行中找到这些“符文”:

   https://dencode.com/string

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接