Bagaimana cara menghapus karakter non-ascii dari nama file?

5

Saya memiliki beberapa file dengan nama yang berisi berbagai karakter Unicode. Saya ingin mengganti nama mereka menjadi hanya berisi karakter ASCII yang "dapat dicetak" (32-126).

Misalnya,

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

Atau untuk poin bonus, transkrip ke karakter terdekat

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

Idealnya mencari jawaban yang tidak memerlukan alat pihak ke-3. (Sunting: Skrip dianjurkan; Saya hanya mencoba untuk menghindari aplikasi niche shareware yang perlu diinstal untuk bekerja)


Cuplikan shell daya yang menemukan file yang saya ingin ubah namanya:

gci -recurse | dimana {$ _. Nama -match "[^ \ u0020- \ u007E]"}

Pertanyaan python serupa yang belum terjawab - https://stackoverflow.com/questions/17870055/how-to-rename-a-file-with-non-ascii-character-encoding-to-ascii

RJFalconer
sumber
1
Tidak ada yang namanya "extended ASCII".
kinokijuf
1
@kinokijuf, katakan itu pada semua orang .
Synetech
1
@kinokijuf, dan tentu saja, tidak ada yang ada sebelum Windows NT.
Synetech
1
@kinokijuf, Synetech benar. Kumpulan kode ASCII yang diperluas telah ada selama lebih dari satu dekade ketika Windows NT dikirimkan. Setiap program DOS yang dikenal manusia menggunakan set ASCII yang diperluas.
Roger
2
@ Kinokijuf, ada halaman kode sekarang. Itu tidak berselisih. DOS menambahkan halaman dukungan kode hanya di DOS 3.3. Namun, rangkaian karakter ASCII yang diperluas dibangun ke dalam ROM dari adapter tampilan PC IBM asli. Lihat situs ini untuk info lebih lanjut.
Roger

Jawaban:

1

Saya menemukan topik serupa sini pada Stack Overflow.

Dengan kode berikut sebagian besar karakter akan diterjemahkan ke "karakter terdekat" mereka. Meskipun saya tidak bisa mendapatkan diterjemahkan. (Mungkin ya, saya tidak bisa membuat nama file di prompt dengan itu;) The ß juga tidak diterjemahkan.

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

Edit:

Saya menambahkan beberapa kode untuk memeriksa apakah nama file sudah ada dan tambahkan (1), (2) dll ... jika ya. (Tidak cukup pintar untuk mendeteksi yang sudah ada (1) dalam nama file yang akan diganti nama sehingga dalam hal ini Anda akan mendapatkan (1) (1). Tapi seperti biasa ... semuanya bisa diprogram;)

Edit 2 :

Ini yang terakhir untuk malam ini ...

Yang ini memiliki fungsi berbeda untuk mengganti karakter. Juga menambahkan garis untuk mengubah karakter yang tidak dikenal suka ß dan misalnya untuk _.

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
  }
}
Rik
sumber
The ß also does not get translated. Mungkin karena eszett seharusnya dipetakan ss yang mana dua karakter. (Baik itu atau untuk B yang akan menjadi bodoh jika Anda tidak mencoba menggunakan 1337-berbicara.) Jelas tidak ada pemetaan bawaan, jadi Anda harus menanganinya secara terpisah.
Synetech
Terima kasih atas semua waktu yang Anda berikan. Berhasil.
RJFalconer
2

Saya percaya ini akan berhasil ...

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

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

Saya tidak memiliki rentang nama file ASCII untuk diuji.

Austin T French
sumber
Anda dapat dengan mudah membuat beberapa file uji klik kanan → Dokumen Teks Baru kemudian ketik beberapa karakter ASCII yang dicampur dengan beberapa karakter ANSI / Unicode yang diperluas.
Synetech
2
Saya hanya berlari sebuah tes dengan sebagian besar permutasi. Tidak mengherankan, ini berfungsi sebagian besar, tetapi Anda mungkin mengalami kesalahan jika nama file ASCII saja bertentangan dengan nama file yang ada (yang juga bisa terjadi jika file lain diganti namanya, mis., resumé1.doc, resumé2.doc, resumé.doc, dll.)
Synetech