Saya perlu mengganti beberapa karakter yang tidak dapat dicetak dengan spasi dalam file.
Secara khusus, semua karakter dari 0x00
hingga 0x1F
, kecuali 0x09
(TAB), 0x0A
(baris baru), 0x0D
(CR)
Sampai sekarang, saya hanya perlu mengganti 0x00
karakter. Karena OS saya sebelumnya adalah AIX (tanpa perintah GNU), saya tidak dapat menggunakan sed
(well, saya bisa tetapi memiliki beberapa keterbatasan). Jadi, saya menemukan perintah berikutnya menggunakan perl
, yang berfungsi seperti yang diharapkan:
perl -p -e 's/\x0/ /g' $FILE_IN > $FILE_OUT
Sekarang saya sedang bekerja di Linux, jadi saya diharapkan dapat menggunakan sed
perintah.
Pertanyaan saya:
Apakah perintah ini sesuai untuk mengganti karakter-karakter itu? Saya mencoba, dan tampaknya berhasil, tetapi saya ingin memastikan:
perl -p -e 's/[\x00-\x08\x0B\x0C\x0E-\x1F]/ /g' $FILE_IN > $FILE_OUT
Saya pikir
perl -p
berfungsi sebagaised
. Jadi, mengapa perintah sebelumnya berfungsi (setidaknya, itu tidak gagal), dan yang berikutnya tidak?sed -e 's/[\x00-\x08\x0B\x0C\x0E-\x1F]/ /g' $FILE_IN > $FILE_OUT
Ini memberitahu saya:
sed: -e ekspresi # 1, char 34: Karakter susunan tidak valid
perl -p
mencetak produk akhirstdin
setelah melakukan operasi yang Anda inginkan, dalam hal ini hanya penggantian.sed
Regex mungkin berbeda dariperl
.Jawaban:
Itu pekerjaan yang khas untuk
tr
:Dalam kasus Anda, ini tidak berfungsi
sed
karena Anda berada di lokal di mana rentang tersebut tidak masuk akal. Jika Anda ingin bekerja dengan nilai byte sebagai lawan dari karakter dan di mana urutannya didasarkan pada nilai numerik dari byte tersebut, taruhan terbaik Anda adalah menggunakan C locale . Kode Anda akan bekerja denganLC_ALL=C
GNUsed
, tetapi menggunakansed
(apalagiperl
) agak berlebihan di sini (dan itu\xXX
tidak portabel di seluruhsed
implementasi sementaratr
pendekatan ini POSIX).Anda juga dapat mempercayai ide lokal Anda tentang apa saja karakter yang dapat dicetak dengan:
Tetapi dengan GNU
tr
(seperti yang biasanya ditemukan pada sistem berbasis Linux), yang hanya berfungsi di lokal di mana karakter adalah byte tunggal (jadi biasanya, bukan UTF-8).Di lokal C, itu juga mengecualikan DEL (0x7f) dan semua nilai byte di atas (tidak dalam ASCII).
Di lokal UTF-8, Anda bisa menggunakan GNU
sed
yang tidak memiliki masalah yangtr
dimiliki GNU :(catat bahwa itu
\r
,\t
bukan standar, dan GNUsed
tidak akan mengenalinya jikaPOSIXLY_CORRECT
ada di lingkungan (akan memperlakukan mereka sebagai backslash, r dan t menjadi bagian dari set seperti yang POSIX minta)).Itu tidak akan mengkonversi byte yang tidak membentuk karakter yang valid jika ada.
sumber
tr
dilakukan perintah. Saya mengerti (kurang lebih) apaLC_ALL = C
itu, tetapi tidak semuanya. Meskipun demikiantr -d
menghapus karakter tersebut, tetapi saya ingin mengganti dengan spasi. Maaf, judul salah. Saya baru sadar, ketika @don_crissti dimodifikasi.XCOM
. Sebagai contoh, non-ASCII-karakter sepertiÉ
dikodifikasikan (menggunakanod -xa
) sebagai0xC9
, jadi saya kira itu akan menjadiISO-8859-1
.locale -a
untuk melihat apakah ada lokal dengan iso8859-1 sebagai charset di sistem Anda dan gunakanLC_CTYPE=<that-locale> tr ...[:print:]...
untuk mengonversi non-printable di lokal itu. Atau Anda dapat menggunakan iconv untuk mengonversi file-file itu ke rangkaian karakter lokal Anda.LC_ALL=en_US.iso88591
. Jadi, perintah Anda (tr -c '[:print:]\t\r\n' '[ *]'
) berfungsi sempurna tanpa mengubah lokal atau mengonversi file. Terima kasih banyak.Saya mencoba mengirim pemberitahuan melalui libnotify, dengan konten yang mungkin mengandung karakter yang tidak dapat dicetak. Solusi yang ada tidak cukup berfungsi untuk saya (menggunakan daftar putih karakter menggunakan
tr
karya, tetapi menghapus semua karakter multi-byte).Inilah yang berhasil, saat melewati tes 💩:
sumber