PowerShell中Select-Object -Unique将æ识别为ae的原因及解决方法
问题复现
使用如下PowerShell代码做去重测试:
$Test = @('ae','æ') $Test | Select-Object -Unique
执行后输出仅为:
ae
实际使用需求为不将"ae"与"æ"判定为相等字符串,默认去重逻辑不符合预期。
产生原因
PowerShell默认的字符串比较逻辑遵循当前线程所属文化区域的语素等价规则,而非逐Unicode码点的精确字节比较:
æ是拉丁语系中常见的ae合字,在默认的西文文化比较规则中,二者会被判定为语义等价,直接用'ae' -eq 'æ'测试也会返回$true。Select-Object -Unique做去重判断时,直接调用了PowerShell默认的比较逻辑,因此会将两个字符串识别为重复项,仅保留序列中第一个出现的值。
规避方案
核心思路是替换默认的文化相关比较规则,使用Ordinal(序数值)比较规则做精确匹配,逐位对比字符串的Unicode码点,不做任何语素等价映射,常用实现方式有两种:
- 调用.NET内置LINQ的Distinct方法,直接指定精确比较器,写法最简洁:
[System.Linq.Enumerable]::Distinct( [string[]]$Test, [System.StringComparer]::Ordinal ) - 如果需要适配管道流式处理,可以用泛型哈希集自行实现去重逻辑,同样指定Ordinal比较规则:
$uniqueSet = [System.Collections.Generic.HashSet[string]]::new( [System.StringComparer]::Ordinal ) $Test | ForEach-Object { if ($uniqueSet.Add($_)) { $_ } }
两种方式执行后都会完整返回ae和æ两个值,符合精确去重的要求。额外注意:后续做字符串相等判断时,如果需要避免这类合字、重音字符的等价匹配,不要直接使用默认的-eq运算符,可以调用字符串的Equals方法指定比较规则:$strA.Equals($strB, [System.StringComparison]::Ordinal)。
内容的提问来源于stack exchange,提问作者Anders
相关产品推荐
相关产品推荐

