วิธีการทำให้ tr ตระหนักถึงอักขระที่ไม่ใช่ ascii (unicode)


36

ฉันกำลังพยายามลบอักขระบางตัวออกจากไฟล์ (UTF-8) ฉันใช้trเพื่อจุดประสงค์นี้:

tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat 

ไฟล์มีอักขระต่างประเทศบางตัว (เช่น "Латвийская" หรือ "àé") trดูเหมือนจะไม่เข้าใจพวกเขามันถือว่าพวกเขาเป็นที่ไม่ใช่อัลฟาและลบออกด้วย

ฉันพยายามเปลี่ยนการตั้งค่าภาษาของฉัน:

LC_CTYPE=C LC_COLLATE=C tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat
LC_CTYPE=ru_RU.UTF-8 LC_COLLATE=C tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat
LC_CTYPE=ru_RU.UTF-8 LC_COLLATE=ru_RU.UTF-8 tr -cs '[[:alpha:][:space:]]' ' ' <testdata.dat

น่าเสียดายที่ไม่มีสิ่งเหล่านี้ทำงาน

ฉันจะทำให้trเข้าใจ Unicode ได้อย่างไร

คำตอบ:


29

ที่เป็นที่รู้จักกัน ( 1 , 2 , 3 , 4 , 5 , 6 ) ข้อ จำกัด trของการดำเนินงานของกนู

ไม่ใช่ว่าไม่รองรับอักขระต่างประเทศไม่ใช่ภาษาอังกฤษหรือไม่ใช่ ASCII แต่ไม่รองรับอักขระหลายไบต์

อักขระซิริลลิกเหล่านั้นจะถือว่าใช้ได้ถ้าเขียนในชุดอักขระ iso8859-5 (ไบต์เดียวต่ออักขระ) (และโลแคลของคุณใช้ชุดอักขระนั้น) แต่ปัญหาของคุณคือคุณใช้ UTF-8 ซึ่งไม่ใช่ ASCII อักขระถูกเข้ารหัสใน 2 หรือมากกว่าไบต์

GNU มีแผน (ดูเพิ่มเติม ) เพื่อแก้ไขปัญหานี้และงานนั้นกำลังดำเนินการอยู่

FreeBSD หรือ Solaris trไม่มีปัญหา


ในเวลาเฉลี่ยสำหรับกรณีการใช้งานส่วนใหญ่trคุณสามารถใช้ GNU sed หรือ GNU awk ซึ่งรองรับอักขระหลายไบต์

ตัวอย่างเช่น:

tr -cs '[[:alpha:][:space:]]' ' '

สามารถเขียนได้:

gsed -E 's/( |[^[:space:][:alpha:]])+/ /'

หรือ:

gawk -v RS='( |[^[:space:][:alpha:]])+' '{printf "%s", sep $0; sep=" "}'

วิธีแปลงระหว่างตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ ( tr '[:upper:]' '[:lower:]'):

gsed 's/[[:upper:]]/\l&/g'

(นั่นlคือตัวพิมพ์เล็กLไม่ใช่1ตัวเลข)

หรือ:

gawk '{print tolower($0)}'

สำหรับการพกพาperlเป็นอีกทางเลือกหนึ่ง:

perl -Mopen=locale -pe 's/([^[:space:][:alpha:]]| )+/ /g'
perl -Mopen=locale -pe '$_=lc$_'

หากคุณรู้ว่าข้อมูลสามารถแสดงในชุดอักขระไบต์เดียวจากนั้นคุณสามารถประมวลผลข้อมูลในชุดอักขระนั้น:

(export LC_ALL=ru_RU.iso88595
 iconv -f utf-8 |
   tr -cs '[:alpha:][:space:]' ' ' |
   iconv -t utf-8) < Russian-file.utf8

1
ฉันยอมรับคำถามของคุณเนื่องจากข้อมูลเกี่ยวกับ tr ฉันได้แก้ไขปัญหาแล้วและนำคำถามเกี่ยวกับวิธีการแก้ปัญหาออกไป (ดังนั้นผู้ที่มองหา tr จะพบเฉพาะข้อมูลเกี่ยวกับ tr ไม่ใช่ปัญหาโดยพลการ) หากคุณสามารถลบโซลูชันด้วยเช่นกันเนื่องจากมันไม่ต้องการอีกต่อไปฉันจะขอบคุณ
MatthewRock

3
@ MatthewRock ฉันได้เก็บมันไว้แล้ว แต่ป้อนกลับอีกครั้งและสร้างคำที่กว้างกว่าเดิมหากการให้คำศัพท์รอบตัวจะเป็นประโยชน์กับคนที่มีปัญหาเดียวกัน
Stéphane Chazelas

คุณจะได้รับความคิดว่าซีริลลิกเข้ารหัสแบบปกติใน ISO 8859-5 ที่ไหน คุณเคยเห็นข้อความภาษารัสเซียเป็นอะไรนอกจาก Unicode หรือไม่?
Incnis Mrsi

9
@IncnisMrsi สิ่งที่สำคัญที่นี่คือ ISO 8859-5 เป็นหนึ่งในชุดอักขระแบบไบต์ที่มีอักขระซิริลลิกเหล่านั้น ไม่ว่าจะเป็นการใช้งานอย่างแพร่หลายหรือไม่เกี่ยวข้องกับที่นี่ หากคุณมีโลแคลที่มีชุดอักขระ KOI-R หรือ window-1251 ให้ใช้แทน
Stéphane Chazelas

@IncnisMrsi ภาษารัสเซียบนเว็บมักจะเข้ารหัสใน UTF-8 (หรือเป็นครั้งคราวใน Windows-1251) แต่เพียงเพราะเรารู้สึกถึงความเจ็บปวดของการเข้ารหัสไบต์เดียวจำนวนมากในช่วงต้น ต่อไปนี้เป็น (ประมาณ 1998) หน้าเว็บของโบราณด้วย (ไม่ทำงาน) การเข้ารหัสสลับ: sch57.ru/collect
Alex Shpilkin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.