这个,之前放在PowerShell代码备忘录那边,但是这例子的体量确实太大,索性拆出来。
另外就是,这办法其实没什么必要用www
直接用VbStrConv就行了:文字列を全角/半角に変換するには?(VB.NET関数活用)
环境
操作系统Win10 1909,PowerShell版本($PSVersionTable.PSVersion.Major
)是5,$PSCulture
和$PSUICulture
均为ja-JP。另外有C#代码,使用dotNET Core 3.1。
另外在PowerShell 7.0.0-rc.1($PSVersionTable.PSVersion.ToString()
)上也测试成功了。
参考
实践
PowerShell
Program.ps1
Set-Variable -Name LOCALE_SYSTEM_DEFAULT -Value ([uint]0x0800) -Option Constant
Set-Variable -Name LCMAP_HALFWIDTH -Value ([uint]0x00400000) -Option Constant
Set-Variable -Name LCMAP_FULLWIDTH -Value ([uint]0x00800000) -Option Constant
$signature = @"
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern int LCMapString(
uint Locale,
uint dwMapFlags,
string lpSrcStr,
int cchSrc,
StringBuilder lpDestStr,
int cchDest);
"@
$mapString = Add-Type `
-MemberDefinition $signature `
-Name "Winnls" `
-Namespace "Kernel32" `
-UsingNamespace "System.Text" `
-PassThru
function ToHalfWidth {
param (
[string]
$fullWidth
)
$sb = [System.Text.StringBuilder]::new()
$mapString::LCMapString(
$LOCALE_SYSTEM_DEFAULT,
$LCMAP_HALFWIDTH,
$fullWidth,
-1,
$sb,
$sb.Capacity) | Out-Null
return $sb.ToString()
}
function ToFullWidth {
param (
[string]
$halfWidth
)
$sb = [System.Text.StringBuilder]::new()
$mapString::LCMapString(
$LOCALE_SYSTEM_DEFAULT,
$LCMAP_FULLWIDTH,
$halfWidth,
-1,
$sb,
$sb.Capacity) | Out-Null
return $sb.ToString()
}
$fullWidth = "ウィキペディア"
$halfWidth = "ウィキペディア"
$f2h = ToHalfWidth($fullWidth);
$h2f = ToFullWidth($halfWidth);
Write-Host "Full Width: $fullWidth($($fullWidth.Length))`tHalf Width: $f2h($($f2h.Length))"
Write-Host "Half Width: $halfWidth($($halfWidth.Length))`tFull Width: $h2f($($h2f.Length))"
运行结果:
Full Width: ウィキペディア(7) Half Width: ウィキペディア(9)
Half Width: ウィキペディア(9) Full Width: ウィキペディア(7)
C Sharp
这个实际是在C#(dotNET Core 3.1的)那边做了实验之后再转到pwsh的。
Program.cs
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace ChrWidthConverter
{
class Program
{
private const uint LOCALE_SYSTEM_DEFAULT = 0x0800;
private const uint LCMAP_HALFWIDTH = 0x0040_0000;
private const uint LCMAP_FULLWIDTH = 0x0080_0000;
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern int LCMapString(
uint Locale,
uint dwMapFlags,
string lpSrcStr,
int cchSrc,
StringBuilder lpDestStr,
int cchDest);
static void Main(string[] args)
{
var fullWidth = "ウィキペディア";
var halfWidth = "ウィキペディア";
var f2h = ToHalfWidth(fullWidth);
var h2f = ToFullWidth(halfWidth);
Console.WriteLine($"Full Width: {fullWidth}({fullWidth.Length})\tHalf Width: {f2h}({f2h.Length})");
Console.WriteLine($"Half Width: {halfWidth}({halfWidth.Length})\tFull Width: {h2f}({h2f.Length})");
}
public static string ToHalfWidth(string fullWidth)
{
var sb = new StringBuilder();
LCMapString(
LOCALE_SYSTEM_DEFAULT,
LCMAP_HALFWIDTH,
fullWidth,
-1,
sb,
sb.Capacity);
return sb.ToString();
}
public static string ToFullWidth(string halfWidth)
{
var sb = new StringBuilder();
LCMapString(
LOCALE_SYSTEM_DEFAULT,
LCMAP_FULLWIDTH,
halfWidth,
-1,
sb,
sb.Capacity);
return sb.ToString();
}
}
}
运行(dotnet run
)之后的结果和上面一致。
后记
其实最终只是再熟悉一遍P/Invoke而已。PowerShell那边有些写法需要斟酌一下才好,尤其是Add-Type -MemberDefinition
的运用——虽然省事,不熟悉的话反倒很麻烦,倒不如写C#出个dll给PowerShell调。