Hapus karakter unicode yang tidak dikenal dari file teks - sed, metode bash / shell lainnya


9

Saya perlu mencari dan mengganti semua kemunculan karakter yang tidak dikenal di beberapa file dengan nama yang sama.

Membuka file seperti itu dengan vi, saya membaca kode <91> untuk karakter itu. Membuka mereka dengan nano, saya membaca "tanda tanya" dalam berlian (black rhumble).

Saya ingin mengganti karakter yang tidak dikenal tersebut dengan kutipan ('). Saya mencoba banyak cara tanpa hasil.

Saya mencoba:

find ./ -name filename.txt -exec perl -i~ -pe "s/\x91/'/" {} \;



find ./ -name filename.txt -exec sed -i "s/\x91/'/g" {} \;

Sunting Informasi lebih lanjut tentang karakter:

Hexadecimal: 91 68 74 74
Decimal: 145 104 116 116
Octal: 221 150 164 164
Binary: 10010001 01101000 01110100 01110100

LC_ALL=C sed -n l < file

\221

Jika Anda membutuhkan lebih banyak, tanyakan!


Dengan cara apa sed -i "s/\x91/'/g"itu filetidak berhasil?
Stéphane Chazelas

Jawaban:


3

Anda harus melihat menggunakan hexdump -Cdan menemukan byte di sekitarnya. Menganggap UTF-8, yang vimenunjukkan sebagai <91>(desimal 145, titik unicode yang tidak berarti dalam teks) akan menjadi dua byte, 0xc2 dan 0x91.

Tersirat bahwa substitusi Anda tidak berfungsi sama sekali, tetapi jika yang Anda lakukan hanya mengganti 0x91 dengan 0x27, Anda akan membatalkan UTF-8 (byte kedua dari urutan dua byte selalu memiliki set bit tinggi, yaitu > = 0x80). Ini mungkin mempersulit analisis Anda, meskipun vikemudian harus menunjukkannya sebagai ?'.

Yang mengatakan, saya menguji ini dan berhasil:

#!/usr/bin/perl
use strict;
use warnings FATAL => qw(all);

my $data = "";
my $file = $ARGV[0];

while (<>) {
    s/\xc2\x91/'/g;
    $data .= $_;
}

open my $out, '>', $file || die "Could not write $file.";
print $out $data;
close $out;  

Jika $ARGV[0]ada saat <>direferensikan, perl mengeluarkan ini dari tumpukan argumen dan menjadikannya sebagai filepath untuk digunakan untuk input (saya menemukan skrip pendek lebih mudah untuk men-tweak dan bekerja dengan dari satu liners, BTW). Ini terakumulasi dalam memori (baik selama file tidak besar), sedangkan perl -imengganti nama file asli untuk menghindari kondisi balapan sunting di tempat (lihat perldoc perlrun).

Jadi Anda bisa menggunakannya:

  find . -name "*.txt" -exec whatever.pl {} +

tidak bekerja, tanda tanya tetap ...
jasmines

Apakah Anda memeriksanya hexdump -Cuntuk melihat apa yang sebenarnya ada di sana?
goldilocks

3

Jika memang karakter U + 0091 (0xc2 0x91 dalam pengkodean UTF-8) dan bukan byte 0x91, maka:

PERLIO=:utf8 perl -pi -e "s/\N{U+0091}/'/g" file

Akan mengubahnya menjadi '.

Dengan GNU sed:

sed -i "s/\xc2\x91/'/" file

Edit:

Namun, dalam kasus Anda, file tersebut tidak dalam UTF-8. Karakter UTF-8 adalah satu byte, hanya untuk karakter ASCII (untuk nilai 0 hingga 0x7F). Karakter lain diwakili oleh dua atau lebih byte yang nilainya lebih besar dari 0x7F. Jadi satu 0x91byte, tanpa byte lebih besar dari 0x7F di sekitarnya tidak dapat ditemukan dalam file utf-8.

Kemungkinan besar, file Anda dalam satu set karakter byte tunggal, kemungkinan besar beberapa Microsoft seperti windows-1252 .

Di windows-1252, 0x91 adalah karakter kutipan tunggal kiri. Setara unicode adalah U + 2018 yang ditulis dalam UTF-8 0xe2 0x80 0x98.

Jika Anda ingin mengonversi file Anda ke UTF-8, yang terbaik mungkin adalah menggunakan alat khusus untuk itu. Suka:

recode windows-1252..utf8 < file

Atau:

iconv -f windows-1252 -t utf-8 < file

Atau jika Anda ingin melakukannya untuk setiap filename.txt:

find . -type f -name filename.txt -exec sh -Cc '
  for file do
    mv "$file" "$file~" &&
      iconv -f windows-1252 -t utf-8 < "$file~" > "$file"
  done' sh {} +

tidak bekerja, tanda tanya tetap ...
jasmines

@ jasmines Maka itu bukan U+0091. Silakan tambahkan output LC_ALL=C sed -n l < fileke pertanyaan.
Stéphane Chazelas

tampaknya \ 221
jasmines

Saya tidak dapat mengonversi karena bukan satu file ... Saya perlu mengelompokkan dan mencari dan mengganti secara rekursif.
jasmines
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.