ลบอักขระยูนิโค้ดที่ไม่รู้จักออกจาก textfiles - sed วิธีทุบตี / bash อื่น ๆ


9

ฉันต้องการค้นหาและแทนที่อักขระที่ไม่รู้จักทั้งหมดในบางไฟล์ที่มีชื่อเหมือนกัน

เมื่อเปิดไฟล์ดังกล่าวด้วย vi ฉันอ่านรหัส <91> สำหรับตัวละครนั้น เมื่อเปิดมันด้วยนาโนฉันอ่าน "เครื่องหมายคำถาม" ในรูปเพชร (สีดำสลัว)

ฉันต้องการแทนที่ตัวละครที่ไม่รู้จักด้วยเครื่องหมายคำพูด (') ฉันพยายามหลายวิธีโดยไม่มีโชค

ฉันเหนื่อย:

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



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

แก้ไข ข้อมูลเพิ่มเติมเกี่ยวกับตัวละคร:

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

ถ้าคุณต้องการมากกว่านี้ถาม!


วิธีนี้sed -i "s/\x91/'/g"ใช้fileไม่ได้ผล?
Stéphane Chazelas

คำตอบ:


3

คุณควรมีลักษณะการใช้hexdump -Cและค้นหาไบต์รอบ ๆ สันนิษฐาน UTF-8 สิ่งที่viแสดงเป็น<91>(ทศนิยม 145 จุด Unicode ที่ไม่มีความหมายในข้อความ) จะเป็นสองไบต์ 0xc2 และ 0x91

มันส่อให้เห็นว่าการแทนที่ของคุณไม่ทำงานเลย แต่ถ้าสิ่งที่คุณทำคือแทนที่ 0x91 ด้วย 0x27 คุณจะทำให้ UTF-8 ใช้ไม่ได้ (ไบต์ที่สองของลำดับสองไบต์มีชุดบิตสูงเสมอเช่นคือ > = 0x80) ซึ่งอาจมีความซับซ้อนการวิเคราะห์ของคุณแม้ว่าแล้วควรจะแสดงเป็นvi?'

ที่กล่าวว่าฉันทดสอบและใช้งานได้:

#!/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;  

ถ้า$ARGV[0]มีอยู่เมื่อ<>มีการอ้างอิง, perl pops นี้ปิดกองอาร์กิวเมนต์และใช้เป็น filepath ที่จะใช้สำหรับการป้อนข้อมูล (ฉันพบสคริปต์สั้นง่ายต่อการปรับแต่งและทำงานกับมากกว่าหนึ่ง liners, BTW) สิ่งนี้จะสะสมอยู่ในหน่วยความจำ (ดีตราบใดที่ไฟล์ไม่ใหญ่มาก) ในขณะที่perl -iเปลี่ยนชื่อไฟล์ต้นฉบับเพื่อหลีกเลี่ยงสภาวะการแข่งขันแบบแก้ไขในสถานที่ (ดูperldoc perlrun)

ดังนั้นคุณสามารถใช้:

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

มันใช้งานไม่ได้เครื่องหมายคำถามยังคงอยู่ ...
jasmines

คุณเช็คอินhexdump -Cเพื่อดูว่ามีอะไรเกิดขึ้นจริงหรือ
goldilocks

3

หากเป็นอักขระ U + 0091 (0xc2 0x91 ในการเข้ารหัส UTF-8) และไม่ใช่ไบต์ 0x91 ให้ทำดังนี้:

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

'จะแปลงเป็น

ด้วย GNU sed:

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

แก้ไข:

อย่างไรก็ตามในกรณีของคุณไฟล์ไม่ได้อยู่ใน UTF-8 อักขระ UTF-8 เป็นหนึ่งไบต์สำหรับอักขระ ASCII เท่านั้น (สำหรับค่า 0 ถึง 0x7F) ตัวละครอื่น ๆ 0x7Fโดยมีตัวแทนสองคนหรือมากกว่าไบต์ที่มีค่ามากกว่า ดังนั้น0x91ไบต์ที่ไม่มีไบต์มากกว่า 0x7F รอบ ๆ จะไม่สามารถพบได้ในไฟล์ utf-8

มีแนวโน้มที่ไฟล์ของคุณอยู่ในไบต์เดี่ยวชุดอักขระส่วนใหญ่มีแนวโน้มบางคนเช่นไมโครซอฟท์1252 หน้าต่าง

ใน windows-1252, 0x91 เป็นอักขระเครื่องหมายคำพูดเดี่ยวทางซ้าย เทียบเท่า Unicode เป็น U + 2018 ซึ่ง UTF-8 0xe2 0x80 0x98เป็นลายลักษณ์อักษร

หากคุณต้องการแปลงไฟล์ของคุณเป็น UTF-8 สิ่งที่ดีที่สุดคือการใช้เครื่องมือเฉพาะสำหรับสิ่งนั้น ชอบ:

recode windows-1252..utf8 < file

หรือ:

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

หรือถ้าคุณต้องการที่จะทำมันสำหรับทุกคน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 {} +

มันใช้งานไม่ได้เครื่องหมายคำถามยังคงอยู่ ...
jasmines

@jasmines U+0091แล้วก็ไม่ได้เป็น โปรดเพิ่มผลลัพธ์ของLC_ALL=C sed -n l < fileคำถาม
Stéphane Chazelas

ดูเหมือนจะเป็น \ 221
jasmines

ฉันไม่สามารถแปลงได้เนื่องจากไม่ใช่ไฟล์เดียว ... ฉันต้องแบตช์และค้นหาซ้ำและแทนที่ซ้ำ
jasmines
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.