web-dev-qa-db-ja.com

ファイル名から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

理想的には、サードパーティのツールを必要としない答えを探しています。 (編集:スクリプトを推奨します。動作するためにインストールする必要のあるニッチなシェアウェアアプリを避けようとしています)


名前の変更に関心のあるファイルを見つけるPowerShellスニペット:

gci -recurse |ここで、{$ _。Name-match "[^\u0020-\u007E]"}

未回答の類似python質問- https://stackoverflow.com/questions/17870055/how-to-rename-a-file-with-non-ascii-character-encoding- to-ascii

6
RJFalconer

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
  }
}
1
Rik

私はこれがうまくいくと信じています...

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

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

ただし、テストするASCIIファイル名の範囲はありません。

2
Austin T French