PowerShell 6.2初步实现打字带空格

环境

操作系统Win10 1909,PowerShell版本($PSVersionTable.PSVersion.ToString())6.2.3。$PSCulture$PSUICulture都是ja-JP,用自带终端(这倒不重要。为了避免问题,用例都是在操作文件)。

缘由

可能因为大字报的风格影响到了弹幕(所谓Big Shita Red,底端大红字),“打 字 带 空 格”这样的玩法(起码以前)非常流行。我寻思拿PowerShell整一个玩。

TL;NR

下面的实现其实只是基于code point(码位)而言的,实际上我们更希望基于grapheme(日语那边叫書記素)操作——毕竟我们认为的“一个字”,其实表现出来就是“一个grapheme”而已。

顺便,找到一些好文章:

总而言之,现在看来最方便的办法其实是这样的:

# .\sample.txt
# 🎢柑橘峨嵋酒🎢
#
@([System.Globalization.StringInfo]::GetTextElementEnumerator((Get-Content .\sample.txt))) -join ' ' > .\b.txt
# .\b.txt
# 🎢 柑 橘 峨 嵋 酒 🎢
#

其实用System.Globalization.StringInfo就足够了。文档参见这里

另外,最彻底的办法应该是ICU(International Components for Unicode,不是那个996哦),这边有用例。

啊,我之前大概是做了一些无用功,不过代码倒是值得一看。

代码

D:\work\util\U8ChrList.ps1

<#
U8ChrList Class
#>
class U8ChrList : System.Collections.Generic.List[string] {
    # separator
    static [string]$Separator = ' ';
    # constructor
    U8ChrList([string]$s) {
        [string]$tmp = '';
        $s.ToCharArray() |
            ForEach-Object {
                if ([char]::IsHighSurrogate($_)) {
                    $tmp = [string]$_;
                } elseif ([char]::IsLowSurrogate($_)) {
                    $this.Add($tmp + [string]$_);
                } else {
                    $this.Add([string]$_);
                }
            };
    }

    # implement w/ U8ChrList object
    [string] InsertSeparator() {
        return $this.ToArray() -join [U8ChrList]::Separator;
    }

    # static implement w/o U8ChrList object
    static [string] InsertSeparator([string]$s) {
        [int]$Script:charCounter = 0;
        $matchEvl = {
            [string]$t = $args[0].Groups[0].Value;
            $Script:charCounter += 1;
            if ($Script:charCounter -eq $s.Length `
                    -or [char]::IsHighSurrogate([char]$t)) {
                return $t;
            }
            return $t + [U8ChrList]::Separator;
        };
        [string]$tmp = ([regex]'.').Replace($s, $matchEvl);
        Remove-Variable 'charCounter' -Scope 'Script';
        return $tmp;
    }

}

用例

打开pwsh终端,临时加载驱动器:

New-PSDrive -Name 'W' -PSProvider FileSystem -Root 'D:\work';

顺便cd过去:

Set-Location W:

导入模组:

Import-Module .\util\U8ChrList.ps1

顺便查看一下:

Get-Module -Name U8ChrList
ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     0.0        U8ChrList

D:\work\下,建立sample.txt,内容如下:

🎢柑橘峨嵋酒🎢

正戏(D:\work\a.txt还不存在):

$o = New-Object U8ChrList($s)
$o -join ' ' >> .\a.txt
$o.InsertSeparator() >> .\a.txt
[U8ChrList]::InsertSeparator($s) >> .\a.txt

查看一下D:\work\a.txt

🎢 柑 橘 峨 嵋 酒 🎢
🎢 柑 橘 峨 嵋 酒 🎢
🎢 柑 橘 峨 嵋 酒 🎢

👌です!

后记

至于说为什么写得这么复杂,原因在于.NET自己没提供Utf8String之类的方法,导致遇到超过BMP范围的文字就一定要注意代理对了。

其实吧,要是用(现代的)JavaScript:

console.log([...'🎢柑橘峨嵋酒🎢'].join(' '));

输出

🎢 柑 橘 峨 嵋 酒 🎢

是不是爽多了。

以后再试着分析一下子。

InSb

InSb

只是跟工作和生活相关的记录