如何从文件名中删除非 ASCII 字符?

如何从文件名中删除非 ASCII 字符?

我有几个文件,其名称包含各种 Unicode 字符。我想将它们重命名为仅包含“可打印”的 ASCII 字符 (32-126)。

例如,

Läsmig.txt         //Before
L_smig.txt         //After
Mike’s Project.zip 
Mike_s Project.zip 

或者为了获得加分,转录到最接近的字符

Läsmig.txt
Lasmig.txt
Mike’s Project.zip
Mike's Project.zip

理想情况下,寻找不需要第三方工具的答案。

(编辑:鼓励使用脚本;我只是想避免使用需要安装才能运行的小众共享软件应用程序)


Power shell 代码片段可以找到我想要重命名的文件:

gci -recurse | 其中 {$_.Name -match “[^\u0020-\u007E]”}

未回答的类似 Python 问题 -https://stackoverflow.com/questions/17870055/how-to-rename-a-file-with-non-ascii-character-encoding-to-ascii

答案1

我找到了类似的主题这里在 Stack Overflow 上。

使用以下代码,大多数字符将被翻译为它们的“最接近的字符”。虽然我无法获得翻译。(也许可以,但我无法用它在提示符中创建文件名;)ß也无法翻译。

function Remove-Diacritics {
param ([String]$src = [String]::Empty)
  $normalized = $src.Normalize( [Text.NormalizationForm]::FormD )
  $sb = new-object Text.StringBuilder
  $normalized.ToCharArray() | % {
    if( [Globalization.CharUnicodeInfo]::GetUnicodeCategory($_) -ne [Globalization.UnicodeCategory]::NonSpacingMark) {
      [void]$sb.Append($_)
    }
  }
  $sb.ToString()
}

$files = gci -recurse | where {$_.Name -match "[^\u0020-\u007F]"}
$files | ForEach-Object {
  $newname = Remove-Diacritics $_.Name
  if ($_.Name -ne $newname) {
    $num=1
    $nextname = $_.Fullname.replace($_.Name,$newname)
    while(Test-Path -Path $nextname)
    {
      $next = ([io.fileinfo]$newname).basename + " ($num)" + ([io.fileinfo]$newname).Extension
      $nextname = $_.Fullname.replace($_.Name,$next)
      $num+=1
    }
    echo $nextname
    ren $_.Fullname $nextname
  }
}

编辑:

我添加了一些代码来检查文件名是否已经存在,如果存在(1),则添加(2)等。(它不够智能,无法检测到(1)文件名中已经存在的要重命名的内容,因此在这种情况下您会得到(1) (1)。但一如既往……一切都是可编程的;)

编辑2

这是今晚的最后一个……

这个函数具有替换字符的不同功能。还添加了一行来将未知字符(例如ß和)更改_

function Convert-ToLatinCharacters {
param([string]$inputString)
  [Text.Encoding]::ASCII.GetString([Text.Encoding]::GetEncoding("Cyrillic").GetBytes($inputString))
}

$files = gci -recurse | where {$_.Name -match "[^\u0020-\u007F]"}
$files | ForEach-Object {
  $newname = Convert-ToLatinCharacters $_.Name
  $newname = $newname.replace('?','_')
  if ($_.Name -ne $newname) {
    $num=1
    $nextname = $_.Fullname.replace($_.Name,$newname)
    while(Test-Path -Path $nextname)
    {
      $next = ([io.fileinfo]$newname).basename + " ($num)" + ([io.fileinfo]$newname).Extension
      $nextname = $_.Fullname.replace($_.Name,$next)
      $num+=1
    }
    echo $nextname
    ren $_.Fullname $nextname
  }
}

答案2

我相信这会起作用...

$Files = gci | where {$_.Name -match "[^\u0020-\u007F]"}

$Files | ForEach-Object {
$OldName = $_.Name
$NewName = $OldName -replace "[^\u0020-\u007F]", "_"
ren $_ $NewName
}

但是我没有那么多 ASCII 文件名可供测试。

相关内容