Bagaimana saya bisa mengidentifikasi karakter aneh?

10

Saya mencoba mengidentifikasi karakter aneh yang saya temukan dalam file yang saya kerjakan:

$ cat file
�
$ od file
0000000 005353
0000002
$ od -c file
0000000 353  \n
0000002
$ od -x file
0000000 0aeb
0000002

File ini menggunakan penyandian ISO-8859 dan tidak dapat dikonversi ke UTF-8:

$ iconv -f ISO-8859 -t UTF-8 file
iconv: conversion from `ISO-8859' is not supported
Try `iconv --help' or `iconv --usage' for more information.
$ iconv  -t UTF-8 file
iconv: illegal input sequence at position 0
$ file file
file: ISO-8859 text

Pertanyaan utama saya adalah bagaimana saya bisa menafsirkan output di odsini? Saya mencoba menggunakan halaman ini yang memungkinkan saya menerjemahkan antara representasi karakter yang berbeda, tetapi ia memberi tahu saya bahwa 005353sebagai "titik kode Hex" adalah yang tampaknya tidak benar dan 0aebsebagai "titik kode Hex" adalah yang, sekali lagi, tampaknya salah .

Jadi, bagaimana saya bisa menggunakan salah satu dari tiga opsi ( 355, 005353atau 0aeb) untuk mengetahui karakter apa yang seharusnya mereka wakili?

Dan ya, saya memang mencoba dengan alat Unicode tetapi tampaknya juga bukan karakter UTF yang valid:

$ uniprops $(cat file)
U+FFFD ‹�› \N{REPLACEMENT CHARACTER}
    \pS \p{So}
    All Any Assigned Common Zyyy So S Gr_Base Grapheme_Base Graph X_POSIX_Graph
       GrBase Other_Symbol Print X_POSIX_Print Symbol Specials Unicode

jika saya memahami deskripsi karakter Unicode U + FFFD, itu sama sekali bukan karakter asli tetapi pengganti untuk karakter yang rusak. Yang masuk akal karena file tersebut sebenarnya tidak disandikan UTF-8.

terdon
sumber
5
EB bisa δ di halaman kode 437 , atau Ù di halaman kode 850 , atau ë di 8859-1 ; apakah ada yang masuk akal? ( iconvmengeluh karena Anda tidak menentukan rangkaian karakter sumber, sehingga menggunakan default Anda yang mungkin UTF-8.)
Stephen Kitt
@StephenKitt ya, ëadalah apa yang saya lihat ketika data digunakan pada program lain! Tapi bagaimana saya bisa tahu ini? Bukankah itu di suatu tempat dalam data yang saya berikan? Bagaimana caramu menemukannya? Oh saya telah mencoba iconvdengan -f ISO-8859tetapi mengeluh tentang conversion from ISO-8859' tidak supported`.
terdon
1
Argh! Saya mengerti, saya perlu menggunakan adil ebdan mengabaikan 0xindikator hex atau apa pun itu. Ketidaktahuan saya tentang hal semacam ini sangat mendalam. Bisakah Anda mengirim jawaban yang menjelaskan bahwa @StephenKitt?
terdon
5
Kesalahan penting Anda di sini adalah bahwa ISO-8859 bukan nama penyandian. Itu adalah keluarga penyandian; rupanya, yang Anda cari adalah ISO-8859-1.
tripleee
1
Maka Anda iconvakan berhasil; dan / atau Anda bisa mencarinya misalnya di Wikipedia. Untuk pengkodean yang sangat spesifik ini, fileformat.info/info/unicode/char/00eb/index.htm juga berfungsi (Unicode setara dengan ISO-8859-1 dalam kisaran 128-255, meskipun tentu saja tidak ada pengkodean UTF yang kompatibel dengannya) ).
tripleee

Jawaban:

22

File Anda mengandung dua byte, EB dan 0A dalam hex. Kemungkinan file menggunakan set karakter dengan satu byte per karakter, seperti ISO-8859-1 ; dalam rangkaian karakter itu, EB adalah ë:

$ printf "\353\n" | iconv -f ISO-8859-1
ë

Kandidat lain akan δ di halaman kode 437 , Ù di halaman kode 850 ...

od -xOutputnya membingungkan dalam hal ini karena endianness; pilihan yang lebih baik adalah -t x1yang menggunakan byte tunggal:

$ printf "\353\n" | od -t x1
0000000 eb 0a
0000002

od -xpeta od -t x2yang membaca dua byte sekaligus, dan pada sistem little-endian output byte dalam urutan terbalik.

Ketika Anda menemukan file seperti ini, yang tidak valid UTF-8 (atau tidak masuk akal ketika diartikan sebagai file UTF-8), tidak ada cara bodoh untuk secara otomatis menentukan penyandian (dan set karakter). Konteks dapat membantu: jika itu adalah file yang diproduksi pada PC Barat dalam beberapa dekade terakhir, ada peluang yang wajar untuk disandikan dalam ISO-8859-1, -15 (varian Euro), atau Windows-1252; jika lebih tua dari itu, kemungkinan CP-437 dan CP-850 adalah kandidat. File dari sistem Eropa Timur, atau sistem Rusia, atau sistem Asia, akan menggunakan set karakter berbeda yang saya tidak tahu banyak tentang. Lalu ada EBCDIC ... iconv -lakan mendaftar semua set karakter yang iconvtahu tentang, dan Anda dapat melanjutkan dengan coba-coba dari sana.

(Pada satu titik saya tahu sebagian besar CP-437 dan ATASCII dengan hati, mereka adalah hari-hari.)

Stephen Kitt
sumber
1
OK, di halaman wikipedia yang Anda tautkan, saya bisa melihat yang ëdigambarkan sebagai 00EBdan 234. Apa itu tambahan 00? Dan mengapa tidak 355seperti yang saya harapkan dari odoutput? Saya mencoba mendapatkan jawaban yang lebih umum tentang bagaimana saya dapat menggunakan odoutput untuk mengidentifikasi karakter. Bisakah Anda menjelaskan sesuatu tentang menafsirkan kode hex dan / atau informasi apa yang diperlukan untuk dapat mengidentifikasi karakter yang tidak dikenal (penyandian dan apa pun)?
terdon
EB adalah 353 dalam oktal (bukan 355). Saya akan mencoba untuk menggeneralisasi ...
Stephen Kitt
Ups, maaf, maksudku 353. Jadi 353 adalah representasi oktal, bukan desimal. Argh.
terdon
1
Ya, "o" dalam odsingkatan oktal ;-).
Stephen Kitt
1
Bagaimanapun, (U + FFFD) akan ditampilkan oleh terminal emulator sebagai pengganti byte 0xeb yang tidak membentuk karakter yang valid di UTF-8. Tidak jelas mengapa uniprops $(cat file)(tanda kutip yang hilang btw) akan melaporkan itu (saya tidak tahu tentang unipropsperintah itu). unicode "$(cat file)"pada Debian melakukan output Sequence '\xeb' is not valid in charset 'UTF-8'seperti yang saya harapkan.
Stéphane Chazelas
5

Perhatikan bahwa odadalah singkatan sampah oktal , sehingga 005353adalah dua byte sebagai kata oktal, od -xadalah 0aebdalam heksadesimal sebagai kata, dan isi sebenarnya dari file Anda adalah dua byte ebdan 0adalam heksadesimal, dalam urutan ini.

Jadi keduanya 005353dan 0aebtidak bisa hanya diartikan sebagai "hex code point".

0aadalah umpan baris (LF), dan ebtergantung pada pengodean Anda. filehanya menebak pengodeannya, bisa apa saja. Tanpa informasi lebih lanjut dari mana file itu berasal dll akan sulit untuk mengetahuinya.

dirkt
sumber
Saya menyadari ini karena saya tidak mengerti bagaimana kode poin (atau hex, sebenarnya) bekerja, tetapi bagaimana saya bisa tahu ini? Saya biasanya menggunakan od -ckarena itu menghasilkan output yang saya bisa mengerti. Bagaimana saya bisa menggunakan 355yang menghasilkan untuk mengidentifikasi karakter? Dan mengapa itu dicetak 0aebbukannya eb0ajika 0abaris baru?
terdon
@terdon endianness ... Lihat jawaban saya yang diperbarui.
Stephen Kitt
2

Mustahil untuk menebak dengan akurasi charset file teks 100%.

Alat-alat seperti chardet , firefox , file -i ketika tidak ada informasi charset eksplisit yang didefinisikan (mis. Jika HTML berisi meta charset = ... di kepala, semuanya lebih mudah) akan mencoba menggunakan heuristik yang tidak terlalu buruk jika teksnya cukup besar.

Berikut ini, saya mendemonstrasikan deteksi charset dengan chardet( pip install chardet/ apt-get install python-chardetjika perlu).

$ echo "in Noël" | iconv -f utf8 -t latin1  | chardet
<stdin>: windows-1252 with confidence 0.73

Setelah memiliki calon charset yang baik, kita dapat menggunakan iconv, recodeatau mirip untuk mengubah charset file ke charset "aktif" Anda (dalam kasus saya utf-8) dan melihat apakah itu menebak dengan benar ...

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

Beberapa charset (seperti iso-8859-3, iso-8859-1) memiliki banyak kesamaan - terkadang tidak mudah untuk melihat apakah kita menemukan charset yang sempurna ...

Jadi, sangat penting untuk memiliki metadata yang terkait dengan teks yang relevan (mis. XML).

Joao
sumber
Hmm. Saya tidak dapat mereproduksi di sini, hanya crash. Tetapi bagaimanapun juga, bukankah itu hanya memberi tahu saya penyandian file? Masalah saya adalah mengidentifikasi karakter bukan penyandian file. Saya sudah tahu itu.
terdon
1
Maaf, saya gagal memahami pertanyaan (masalah saya yang biasa adalah mengidentifikasi charset). jika Anda sekarang penyandian, iconv -f ... -t utf-8 akan menunjukkan karakternya?
JJoao
Tidak. Saya tunjukkan penyandian di sana. Ada satu karakter tertentu yang tidak didukung oleh pengkodean itu dan itu adalah karakter yang saya coba identifikasi.
terdon
1
Iso-8859 bukan penyandian! encoding adalah iso-8850-1. iso-8859 adalah standar iso yang mencakup beberapa definisi chaset. Cobafile -i ...
JJoao
1
@terdon, maaf karena bersikeras, tetapi, semua trik yang Anda coba bekerja dengan charset yang tepat. Contoh: iconv -f ISO-8859-1 -t UTF-8 file
JJoao
0
#!/bin/bash
#
# Search in a file, a known (part of a ) String (i.E.: Begrüßung),
# by testing all encodings
#
[[ $# -ne 2 ]] && echo "Usage: encoding-finder.sh FILE fUnKy_CHAR_FOR_SURE_IN_FILE" && exit
FILE=$1
PATTERN=$2
for enc in $( iconv -l | sed 's/..$//') 
do 
    iconv -f $enc -t UTF-8 $FILE  2>/dev/null | grep -m 1 $PATTERN && echo $enc 
done 

Jika saya mendapatkan file, yang berisi, untuk Instance the Word Begrung, saya dapat menyimpulkan bahwa Begrüßung mungkin dimaksudkan. Jadi saya mengonversinya dengan semua encodindgs yang dikenal dan lihat, apakah ada yang ditemukan, yang mengubahnya dengan benar.

Biasanya, ada beberapa pengkodean yang tampaknya cocok.

Untuk file yang lebih panjang, Anda dapat memotong cuplikan alih-alih mengonversi ratusan halaman.

Jadi saya akan menyebutnya

encodingfinder.sh FILE Begrüßung

dan tes skrip, apakah dengan mengubahnya dengan pengkodean yang dikenal, yang mana dari mereka menghasilkan "Begrüßung".

Untuk menemukan karakter seperti itu, biasanya kurang membantu, karena karakter yang funky sering menonjol. Dari konteksnya, kata yang tepat untuk dicari biasanya dapat disimpulkan. Tapi kami tidak ingin memeriksa dengan hexeditor, byte apa ini, dan kemudian mengunjungi tabel pengkodean tak berujung, untuk menemukan pelaku kami. :)

Pengguna tidak diketahui
sumber