แปลงระหว่าง Unicode Normalization Forms บนบรรทัดคำสั่ง unix


22

ใน Unicode ชุดอักขระบางตัวมีการแสดงมากกว่าหนึ่งรายการ

ตัวอย่างเช่นอักขระäสามารถแสดงเป็น

  • "ä" นั่นคือ codepoint U + 00E4 (สองไบต์c3 a4ในการเข้ารหัส UTF-8) หรือ
  • "ä" นั่นคือ codepoints สองตัวคือ U + 0061 U + 0308 (สามไบต์61 cc 88ใน UTF-8)

ตามมาตรฐาน Unicode ทั้งสองเป็นตัวแทนเทียบเท่า แต่ในการที่แตกต่างกัน "รูปแบบการฟื้นฟู" ดูUAX # 15: รูปแบบ

กล่องเครื่องมือยูนิกซ์มีเครื่องมือการแปลงข้อความทุกชนิด, sed , tr , iconv , Perl เป็นที่จดจำ ฉันจะทำการแปลง NF อย่างรวดเร็วและง่ายดายบนบรรทัดรับคำสั่งได้อย่างไร


2
ดูเหมือนว่าจะมีโมดูล "Unicode :: Normalization" สำหรับ Perl ซึ่งควรทำสิ่งนี้: search.cpan.org/~sadahiro/Unicode-Normalize-1.16/Normalize.pm
goldilocks

@goldilocks ถ้ามันมี CLI …ฉันหมายถึงฉันทำperl -MUnicode::Normalization -e 'print NFC(…เอ่ออะไรจะเกิดขึ้นที่นี่ตอนนี้…
mirabilos

คำตอบ:


20

คุณสามารถใช้uconvยูทิลิตี้จากห้องไอซียู การทำให้เป็นมาตรฐานสามารถทำได้ผ่านการทับศัพท์ ( -x)

$ uconv -x any-nfd <<<ä | hd
00000000  61 cc 88 0a                                       |a...|
00000004
$ uconv -x any-nfc <<<ä | hd
00000000  c3 a4 0a                                          |...|
00000003

บน Debian, Ubuntu และอนุพันธ์อื่น ๆuconvอยู่ในlibicu-devแพ็คเกจ สำหรับ Fedora, Red Hat และอนุพันธ์อื่น ๆ และในพอร์ต BSD มันอยู่ในicuแพ็คเกจ


งานนี้ขอบคุณ คุณต้องติดตั้งไลบรารี dev 30M ข้าง ๆ แม้ว่า มีอะไรที่แย่กว่านั้นฉันไม่สามารถหาเอกสารที่เหมาะสมสำหรับ uconv เองได้คุณพบany-nfdที่ไหน ดูเหมือนว่าการพัฒนาของเครื่องมือนี้ได้รับการยกเลิกการปรับปรุงที่ผ่านมาในปี 2005
GLTS

2
@glts ผมพบว่าโดยการเรียกดูผ่านรายการแสดงโดยany-nfd uconv -L
Gilles 'หยุดความชั่วร้าย'

บน Ubuntu ที่ใช้sudo apt install icu-devtoolsเพื่อเรียกใช้uconv -x any-nfcแต่ไม่สามารถแก้ปัญหาที่ง่ายที่สุดได้เช่นbugText.txt ไฟล์ที่มี"Iglésias, Bad-á, Good-á" ที่แปลงโดยuconv -x any-nfc bugText.txt > goodText.txtคงข้อความเดิมไว้
Peter Krauss

7

Python มีunicodedataโมดูลในไลบรารีมาตรฐานของมันซึ่งอนุญาตให้แปลการแทน Unicode ผ่านunicodedata.normalize()ฟังก์ชัน:

import unicodedata

s1 = 'Spicy Jalape\u00f1o'
s2 = 'Spicy Jalapen\u0303o'

t1 = unicodedata.normalize('NFC', s1)
t2 = unicodedata.normalize('NFC', s2)
print(t1 == t2) 
print(ascii(t1)) 

t3 = unicodedata.normalize('NFD', s1)
t4 = unicodedata.normalize('NFD', s2)
print(t3 == t4)
print(ascii(t3))

ทำงานกับ Python 3.x:

$ python3 test.py
True
'Spicy Jalape\xf1o'
True
'Spicy Jalapen\u0303o'

Python ไม่เหมาะสำหรับ shell one liners แต่สามารถทำได้ถ้าคุณไม่ต้องการสร้างสคริปต์ภายนอก:

$ python3 -c $'import unicodedata\nprint(unicodedata.normalize("NFC", "ääääää"))'
ääääää

สำหรับ Python 2.x คุณต้องเพิ่มการเข้ารหัสบรรทัด ( # -*- coding: utf-8 -*-) และทำเครื่องหมายสตริงเป็น Unicode ด้วยอักขระ u:

$ python -c $'# -*- coding: utf-8 -*-\nimport unicodedata\nprint(unicodedata.normalize("NFC", u"ääääää"))'
ääääää

3

ตรวจสอบด้วย hexdump เครื่องมือ:

echo  -e "ä\c" |hexdump -C 

00000000  61 cc 88                                          |a..|
00000003  

แปลงด้วย iconv และตรวจสอบอีกครั้งด้วย hexdump:

echo -e "ä\c" | iconv -f UTF-8-MAC -t UTF-8 |hexdump -C

00000000  c3 a4                                             |..|
00000002

printf '\xc3\xa4'
ä

2
ใช้งานได้กับ macOS เท่านั้น ไม่มี 'utf-8-mac' บน Linux, บน FreeBSDs, และอื่น ๆ , การสลายตัวโดยใช้การเข้ารหัสนี้ไม่เป็นไปตามสเปค ข้อมูลเพิ่มเติม: search.cpan.org/~tomita/Encode-UTF8Mac-0.04/lib/Encode/…
antonone

@antonone ให้ยุติธรรมแม้ว่าจะไม่มีระบบปฏิบัติการที่ระบุไว้ในคำถาม
roaima

1
@roaima ใช่นั่นเป็นเหตุผลที่ฉันคิดว่าคำตอบควรทำงานได้กับทุกระบบที่ใช้ Unix / Linux คำตอบข้างต้นใช้งานได้กับ macOS เท่านั้น หากมีใครกำลังมองหาคำตอบเฉพาะสำหรับ macOS แล้วมันก็จะทำงานได้ในบางส่วน ฉันแค่อยากจะชี้ให้เห็นเพราะวันก่อนฉันเสียเวลาสงสัยว่าทำไมฉันไม่มีutf-8-macบน Linux และถ้านี่เป็นเรื่องปกติ
antonone

3

เพื่อความสมบูรณ์ด้วยperl:

$ perl -CSA -MUnicode::Normalize=NFD -e 'print NFD($_) for @ARGV' $'\ue1' | uconv -x name
\N{LATIN SMALL LETTER A}\N{COMBINING ACUTE ACCENT}
$ perl -CSA -MUnicode::Normalize=NFC -e 'print NFC($_) for @ARGV' $'a\u301' | uconv -x name
\N{LATIN SMALL LETTER A WITH ACUTE}

2

coreutils unormมีแพทช์ที่จะได้รับที่เหมาะสม ทำงานได้ดีสำหรับฉันใน 4byte wchars ติดตามhttp://crashcourse.housegordon.org/coreutils-multibyte-support.html#unorm ปัญหาที่เหลืออยู่นั้นมีระบบ 2 ไบต์ wchar (cygwin, windows, aix และ solaris บน 32 บิต) ซึ่งจำเป็นต้องเปลี่ยน codepoints จากส่วนบน เครื่องบินเป็นคู่ตัวแทนและในทางกลับกันและ libunistring พื้นฐาน / gnulib ยังไม่สามารถจัดการที่

perl มีunicharsเครื่องมือซึ่งทำรูปแบบการทำให้เป็นมาตรฐานต่าง ๆ บน cmdline http://search.cpan.org/dist/Unicode-Tussle/script/unichars


2

มียูทิลิตี้ Perl ที่เรียกว่า Charlint จาก

https://www.w3.org/International/charlint/

ซึ่งทำในสิ่งที่คุณต้องการ คุณจะต้องดาวน์โหลดไฟล์จาก

ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt

หลังจากเปิดใช้งานครั้งแรกคุณจะเห็น Charlint บ่นเกี่ยวกับรายการที่เข้ากันไม่ได้ในไฟล์นั้นดังนั้นคุณจะต้องลบบรรทัดเหล่านั้นออกจาก UnicodeData.txt

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