Powershell如何在文本文件中查找非ASCII字符

8

我正在尝试使用 Powershell 脚本实现以下目标:

  1. 对于文本文件中的每一行,检查该行是否包含非 ASCII 字符
  2. 如果该行包含非 ASCII 字符,则将其输出到单独的文件中
  3. 如果该行不包含非 ASCII 字符,则跳过该行并继续执行下一行

所谓的“非 ASCII 字符”是指非键盘字符,例如带重音符号的字符、来自其他语言的字符等。

示例数据

 - 张伟
 - குழந்தைகளுக்கான பெயர்கள்
 - 日本人の氏名
 - Full Name
 - Léna Rémi

输出数据

 - 张伟
 - குழந்தைகளுக்கான பெயர்கள்
 - 日本人の氏名
 - Léna Rémi

我在其他帖子中找到了用于删除非ASCII字符的正则表达式,但似乎无法使其工作。
请帮忙!
** 编辑 ** 感谢大家的帮助!我已经使用下面的脚本完成了想要的操作。
$nonASCII = "[^\x00-\x7F]"
foreach ($_ in [System.IO.File]::ReadLines($source)){
    if ($_ -cmatch $nonASCII){
        write-output $_ | out-File $output -append        
    }
}

1
你所说的非ASCII字符具体指什么?你使用了哪些编码方式?能否提供一些样本数据以及期望的输出结果? - vonPryz
@vonPryz 我已编辑了我的主线程以进一步阐述我希望实现的内容。 - Arolix
你可以使用否定字符类并测试该类,例如 -match '[^0-9a-z]'。另外,应该有一些指定Unicode字符类的方法,但我不记得了... [害羞] - Lee_Dailey
@Lee_Dailey 我会使用 -cnotmatch。否则,在大写和小写字符之间会有一些有趣的例外情况。 - js2010
@js2010 - 我还没有遇到过那个问题...谢谢你的信息![咧嘴笑] - Lee_Dailey
显示剩余2条评论
3个回答

8
定义一个字符集,包括 ASCII 字符的所有代码点(32 到 127,表示为 [\x20-\x7F]),然后使用 ^ 取反来匹配任何非 ASCII 字符!
现在我们用它来测试我的(非 ASCII)名字:
PS C:\> 'Mathias R. Jessen' -cmatch '[^\x20-\x7F]'
False
PS C:\> 'Mathias Rørbo Jessen' -cmatch '[^\x20-\x7F]'
True

要筛选字符串列表,只需在过滤模式下使用 -cmatch 运算符:

$strings = 'குழந்தைகளுக்கான பெயர்கள்', 'Boring John Doe', 'Léna Rémi'

$nonASCIIstrings = @($strings) -cmatch '[^\x20-\x7F]'

或者如果您想在管道中筛选,请使用Where-Object

$strings |Where-Object {$_ -cmatch '[^\x20-\x7F]'}

4

.NET正则表达式引擎支持“非ASCII字符”概念的直接表达方式:\P{IsBasicLatin}(反之,“ASCII字符”为\p{IsBasicLatin}):

' - 张伟',
' - குழந்தைகளுக்கான பெயர்கள்',
' - 日本人の氏名',
' - Full Name', 
' - Léna Rémi' -cmatch '\P{IsBasicLatin}'
IsBasicLatin是一个示例,它属于一个命名(Unicode)块
上述内容需要使用-cmatch,即-match的区分大小写的变体,[1]这是一个正则表达式匹配运算符,用于输出那些包含至少一个非ASCII范围字符的输入行(数组元素)。
 - 张伟
 - குழந்தைகளுக்கான பெயர்கள்
 - 日本人の氏名
 - Léna Rémi

如果需要一种流式处理解决方案,逐行读取文件并处理,可以将-matchWhere-Object命令结合使用:

Get-Content in.txt | 
  Where-Object { $_ -cmatch '\P{IsBasicLatin}' } |
    Set-Content -Encoding Utf8 out.txt

请注意,使用Get-Content逐行读取文件,而System.IO.File]::ReadLines("$pwd\in.txt")也可以工作,但仅在存在性能问题时才需要。
[1] 原因是在不区分大小写的匹配中,小写ASCII字符ik被认为是ASCII块内外的两者,即'i' -match '\P{IsBasicLatin}''i' -match '\p{IsBasicLatin}'都是$true。有关说明,请参见此答案。向js2010致敬。

2
这里有一个脚本,可以从XML文件中删除非ASCII字符。或许你可以把它作为起点。我删除的是不在空格和波浪线之间的字符,参考ASCII表,同时也不删除制表符。对我而言,ASCII字符的范围是0-127。Get-content会去掉回车符和换行符。
(get-content $args[0]) -replace '[^ -~\t]' | set-content $args[0]

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