วิธีคาดเดาการเข้ารหัสระหว่าง MacRoman, CP1252, Latin1, UTF-8 และ ASCII ได้อย่างน่าเชื่อถือ


99

ในที่ทำงานดูเหมือนว่าจะไม่มีสัปดาห์ใดผ่านไปโดยไม่มีการเชื่อมต่อที่เกี่ยวข้องกับการเข้ารหัสภัยพิบัติหรือหายนะ ปัญหามักเกิดจากโปรแกรมเมอร์ที่คิดว่าสามารถประมวลผลไฟล์ "ข้อความ" ได้อย่างน่าเชื่อถือโดยไม่ต้องระบุการเข้ารหัส แต่คุณทำไม่ได้

ดังนั้นจึงมีการตัดสินใจที่จะห้ามไม่ให้ไฟล์มีชื่อที่ลงท้ายด้วย*.txtหรือ*.text. แนวคิดก็คือส่วนขยายเหล่านั้นทำให้โปรแกรมเมอร์ทั่วไปเข้าใจผิดว่าเป็นความพึงพอใจที่น่าเบื่อเกี่ยวกับการเข้ารหัสและสิ่งนี้นำไปสู่การจัดการที่ไม่เหมาะสม เกือบจะดีกว่าที่จะไม่มีส่วนขยายเลยเพราะอย่างน้อยคุณก็รู้ว่าคุณไม่รู้ว่าคุณมีอะไรบ้าง

อย่างไรก็ตามเราจะไม่ไปไกลขนาดนั้น คุณจะต้องใช้ชื่อไฟล์ที่ลงท้ายด้วยการเข้ารหัสแทน ดังนั้นสำหรับไฟล์ข้อความเช่นเหล่านี้จะเป็นสิ่งที่ชอบREADME.ascii, README.latin1, README.utf8ฯลฯ

สำหรับไฟล์ที่ต้องการนามสกุลเฉพาะหากสามารถระบุการเข้ารหัสภายในไฟล์ได้เช่นใน Perl หรือ Python คุณจะต้องทำเช่นนั้น สำหรับไฟล์เช่นซอร์ส Java ที่ไม่มีสิ่งอำนวยความสะดวกดังกล่าวอยู่ภายในไฟล์คุณจะต้องใส่การเข้ารหัสก่อนนามสกุลเช่นSomeClass-utf8.java.

สำหรับเอาต์พุต UTF-8 เป็นที่ต้องการอย่างยิ่ง

แต่สำหรับการป้อนข้อมูลที่เราจำเป็นต้องคิดหาวิธีที่จะจัดการกับพันไฟล์ใน codebase *.txtของเราชื่อ เราต้องการเปลี่ยนชื่อทั้งหมดให้เข้ากับมาตรฐานใหม่ของเรา แต่เราไม่สามารถมองเห็นพวกมันได้ทั้งหมด ดังนั้นเราจึงต้องการไลบรารีหรือโปรแกรมที่ใช้งานได้จริง

สิ่งเหล่านี้มีหลากหลายใน ASCII, ISO-8859-1, UTF-8, Microsoft CP1252 หรือ Apple MacRoman แม้ว่าเราจะรู้ว่าเราสามารถบอกได้ว่ามีบางอย่างเป็น ASCII หรือไม่และเรามีการเปลี่ยนแปลงที่ดีในการรู้ว่าบางสิ่งอาจเป็น UTF-8 หรือไม่ แต่เราก็นิ่งงันเกี่ยวกับการเข้ารหัส 8 บิต เนื่องจากเราทำงานในสภาพแวดล้อม Unix แบบผสม (Solaris, Linux, Darwin) โดยที่เดสก์ท็อปส่วนใหญ่เป็น Macs เราจึงมีไฟล์ MacRoman ที่น่ารำคาญอยู่ไม่น้อย และโดยเฉพาะอย่างยิ่งปัญหาเหล่านี้

ในบางครั้งฉันกำลังมองหาวิธีที่จะกำหนดวิธีทางโปรแกรมโดยใช้โปรแกรม

  1. ASCII
  2. ISO-8859-1
  3. CP1252
  4. MacRoman
  5. UTF-8

มีไฟล์อยู่และฉันไม่พบโปรแกรมหรือไลบรารีที่สามารถแยกความแตกต่างระหว่างการเข้ารหัส 8 บิตทั้งสามได้อย่างน่าเชื่อถือ เราอาจมีไฟล์ MacRoman มากกว่าพันไฟล์เพียงอย่างเดียวดังนั้นเครื่องตรวจจับชาร์ตที่เราใช้จะต้องสามารถดมกลิ่นเหล่านั้นได้ ไม่มีสิ่งใดที่ฉันสามารถจัดการกลอุบายได้ ฉันมีความหวังอย่างมากสำหรับไลบรารีตัวตรวจจับอักขระ ICUแต่ไม่สามารถจัดการกับ MacRoman ได้ ฉันยังดูโมดูลเพื่อทำสิ่งเดียวกันทั้งใน Perl และ Python แต่มันก็เป็นเรื่องเดียวกันซ้ำแล้วซ้ำเล่า: ไม่รองรับการตรวจจับ MacRoman

ดังนั้นสิ่งที่ฉันกำลังมองหาคือไลบรารีหรือโปรแกรมที่มีอยู่ซึ่งกำหนดได้อย่างน่าเชื่อถือว่าไฟล์อยู่ในการเข้ารหัสห้ารายการใด - และควรยิ่งไปกว่านั้น โดยเฉพาะอย่างยิ่งที่จะมีการแยกแยะความแตกต่างระหว่างสาม 3 บิตการเข้ารหัสฉันได้อ้างถึงโดยเฉพาะอย่างยิ่ง MacRoman ไฟล์นี้มีข้อความภาษาอังกฤษมากกว่า 99% มีภาษาอื่น ๆ บ้าง แต่ไม่มากนัก

หากเป็นรหัสไลบรารีค่ากำหนดภาษาของเราคือให้อยู่ใน Perl, C, Java หรือ Python และเรียงตามลำดับ หากเป็นเพียงโปรแกรมเราก็ไม่สนใจว่าจะใช้ภาษาอะไรตราบเท่าที่มันมาในแหล่งข้อมูลแบบเต็มทำงานบน Unix และไม่มีภาระผูกพัน

มีใครมีปัญหาเกี่ยวกับไฟล์ข้อความแบบเดิมที่เข้ารหัสแบบสุ่มจำนวน zillion นี้หรือไม่? ถ้าเป็นเช่นนั้นคุณพยายามแก้ปัญหาอย่างไรและคุณประสบความสำเร็จเพียงใด นี่เป็นประเด็นสำคัญที่สุดของคำถามของฉัน แต่ฉันยังสนใจด้วยว่าคุณคิดว่าการสนับสนุนให้โปรแกรมเมอร์ตั้งชื่อ (หรือเปลี่ยนชื่อ) ไฟล์ของพวกเขาด้วยการเข้ารหัสไฟล์เหล่านั้นจริงจะช่วยให้เราหลีกเลี่ยงปัญหาในอนาคตได้หรือไม่ มีใครเคยพยายามบังคับใช้สิ่งนี้บนพื้นฐานของสถาบันและถ้าเป็นเช่นนั้นประสบความสำเร็จหรือไม่และเพราะเหตุใด

และใช่ฉันเข้าใจอย่างถ่องแท้ว่าเหตุใดจึงไม่สามารถรับประกันคำตอบที่แน่นอนได้จากลักษณะของปัญหา โดยเฉพาะอย่างยิ่งในกรณีที่มีไฟล์ขนาดเล็กซึ่งคุณมีข้อมูลไม่เพียงพอที่จะดำเนินการต่อ โชคดีที่ไฟล์ของเราไม่ค่อยมีขนาดเล็ก นอกเหนือจากREADMEไฟล์แบบสุ่มส่วนใหญ่อยู่ในช่วงขนาด 50k ถึง 250k และไฟล์อื่น ๆ มีขนาดใหญ่กว่า สิ่งใดก็ตามที่มีขนาดเกินกว่า K จะรับประกันว่าเป็นภาษาอังกฤษ

โดเมนปัญหาคือการขุดข้อความทางชีวการแพทย์ดังนั้นบางครั้งเราจึงจัดการกับองค์กรที่กว้างขวางและมีขนาดใหญ่มากเช่นเดียวกับที่เก็บ Open Access ทั้งหมดของ PubMedCentral ไฟล์ที่ค่อนข้างใหญ่คือ BioThesaurus 6.0 ที่ 5.7 กิกะไบต์ ไฟล์นี้น่ารำคาญเป็นพิเศษเพราะเป็นUTF-8 เกือบทั้งหมด อย่างไรก็ตาม numbskull บางตัวไปและติดอยู่สองสามบรรทัดในนั้นซึ่งอยู่ในการเข้ารหัส 8 บิต - Microsoft CP1252 ฉันเชื่อ ต้องใช้เวลาสักพักก่อนที่คุณจะเดินทางไป :(


ดูstackoverflow.com/questions/4255305/…สำหรับวิธีแก้ปัญหา
mpenkov

คำตอบ:


86

ประการแรกกรณีง่าย ๆ :

ASCII

หากข้อมูลของคุณไม่มีไบต์ที่สูงกว่า 0x7F แสดงว่าเป็น ASCII (หรือการเข้ารหัส ISO646 7 บิต แต่ล้าสมัยมาก)

UTF-8

หากข้อมูลของคุณตรวจสอบความถูกต้องเป็น UTF-8 คุณสามารถสันนิษฐานได้อย่างปลอดภัยว่าเป็น UTF-8 เนื่องจากกฎการตรวจสอบที่เข้มงวดของ UTF-8 ผลบวกปลอมจึงหายากมาก

ISO-8859-1 เทียบกับ windows-1252

ข้อแตกต่างเพียงอย่างเดียวระหว่างการเข้ารหัสทั้งสองนี้คือ ISO-8859-1 มีอักขระควบคุม C1 โดยที่ windows-1252 มีอักขระที่พิมพ์ได้€‚ ƒ„ …†‡ ˆ ‰‰ ‹ŒŽ ''“” • –—˜ ™š› œžŸ. ฉันเคยเห็นไฟล์มากมายที่ใช้เครื่องหมายอัญประกาศหรือขีดกลาง แต่ไม่มีไฟล์ใดที่ใช้อักขระควบคุม C1 ดังนั้นอย่ากังวลกับพวกเขาหรือ ISO-8859-1 เพียงตรวจจับ windows-1252 แทน

ตอนนี้ทำให้คุณมีคำถามเพียงข้อเดียว

คุณแยกแยะ MacRoman จาก cp1252 ได้อย่างไร

นี่เป็นเรื่องที่ยุ่งยากกว่ามาก

อักขระที่ไม่ได้กำหนด

ไบต์ 0x81, 0x8D, 0x8F, 0x90, 0x9D ไม่ได้ใช้ใน windows-1252 หากเกิดขึ้นให้ถือว่าข้อมูลเป็น MacRoman

อักขระที่เหมือนกัน

ไบต์ 0xA2 (¢), 0xA3 (£), 0xA9 (©), 0xB1 (±), 0xB5 (µ) จะเหมือนกันในการเข้ารหัสทั้งสอง หากเป็นไบต์ที่ไม่ใช่ ASCII เท่านั้นก็ไม่สำคัญว่าคุณจะเลือก MacRoman หรือ cp1252

วิธีการทางสถิติ

นับความถี่อักขระ (ไม่ใช่ไบต์!) ในข้อมูลที่คุณทราบว่าเป็น UTF-8 กำหนดอักขระที่พบบ่อยที่สุด จากนั้นใช้ข้อมูลนี้เพื่อพิจารณาว่าอักขระ cp1252 หรือ MacRoman เป็นแบบทั่วไป

ยกตัวอย่างเช่นในการค้นหาฉันเพียงแค่ดำเนินการใน 100 สุ่มบทความวิกิพีเดียภาษาอังกฤษส่วนใหญ่ตัวละครทั่วไปที่ไม่ใช่ ASCII ·•–é°®’èö—เป็น จากข้อเท็จจริงนี้

  • ไบต์ 0x92, 0x95, 0x96, 0x97, 0xAE, 0xB0, 0xB7, 0xE8, 0xE9 หรือ 0xF6 แนะนำ windows-1252
  • ไบต์ 0x8E, 0x8F, 0x9A, 0xA1, 0xA5, 0xA8, 0xD0, 0xD1, 0xD5 หรือ 0xE1 แนะนำ MacRoman

นับจำนวนไบต์ที่แนะนำ cp1252 และไบต์แนะนำของ MacRoman และไปกับสิ่งที่ยิ่งใหญ่ที่สุด


6
ฉันยอมรับคำตอบของคุณเพราะไม่มีใครเสนอตัวได้ดีกว่านี้และคุณทำงานได้ดีในการเขียนประเด็นที่ฉันกำลังแก้ไข ฉันมีโปรแกรมที่จะกำจัดไบต์เหล่านั้นแม้ว่าคุณจะมีจำนวนประมาณสองเท่าที่ฉันคิด
tchrist

10
ในที่สุดก็สามารถใช้สิ่งนี้ได้ ปรากฎว่า Wikipedia ไม่ใช่ข้อมูลการฝึกอบรมที่ดี จากบทความ en.wikipedia แบบสุ่ม 1k ไม่นับส่วน LANGUAGES ฉันได้รับจุดรหัส unASCII 50k แต่การแจกแจงไม่น่าเชื่อถือ: จุดกลางและสัญลักษณ์แสดงหัวข้อย่อยสูงเกินไป & c & c & c ดังนั้นฉันจึงใช้ทุก UTF8 PubMed Open Access corpus, mining + 14M unASCII codepoints ฉันใช้สิ่งเหล่านี้เพื่อสร้างแบบจำลองความถี่สัมพัทธ์ของการเข้ารหัส 8 บิตทั้งหมดซึ่งดูดีกว่าของคุณ แต่ขึ้นอยู่กับแนวคิดนั้น สิ่งนี้พิสูจน์ให้เห็นถึงการคาดเดาอย่างสูงของการเข้ารหัสสำหรับข้อความชีวการแพทย์ซึ่งเป็นโดเมนเป้าหมาย ฉันควรเผยแพร่สิ่งนี้ ขอบคุณ!
tchrist

5
ฉันยังไม่มีไฟล์ MacRoman แต่จะไม่ใช้ CR เนื่องจากตัวคั่นบรรทัดให้การทดสอบที่มีประโยชน์ สิ่งนี้จะใช้ได้กับ Mac OS เวอร์ชันเก่าแม้ว่าฉันจะไม่รู้เกี่ยวกับ OS9 ก็ตาม
Milliways

สวัสดีมันไม่สายเกินไปที่จะตอบ หลังจากอ่านคำตอบนี้ฉันได้ขยายอัญมณีชาร์ล็อตต์ทับทิม ตอนนี้ตรวจพบรูปแบบข้างต้นได้ดี ฉันต่อท้ายคำตอบใหม่พร้อมรหัสหลักนั้นในคำถามนี้stackoverflow.com/a/64276978/2731103
Tom Freudenberg

10

Mozilla nsUniversalDetector (Perl bindings: Encode :: Detect / Encode :: Detect :: Detector ) ได้รับการพิสูจน์แล้วหลายล้านเท่า


ดูเอกสารเพิ่มเติมได้ที่นี่: mozilla.org/projects/intl/detectorsrc.htmlจากที่นั่นขอแนะนำว่าหากคุณเจาะลึกลงไปในเอกสารคุณจะพบชุดอักขระที่รองรับ
Joel Berger

@ Joel: ฉันขุดลงไปในแหล่งที่มา มันเป็นคำถามเกี่ยวกับวาทศิลป์ x-mac-cyrillicได้รับการสนับสนุนx-mac-hebrewมีการกล่าวถึงเป็นระยะเวลานานในความคิดเห็นx-mac-anything-elseไม่ได้รับการกล่าวถึง
John Machin

@ John Machin: แปลกที่ซิริลลิกและฮีบรูได้รับการพยักหน้า แต่ไม่มีอะไรอื่น ฉันแค่โยนในแหล่งเอกสารอื่นฉันไม่ได้อ่านเพิ่มเติมขอบคุณที่ทำเช่นนั้น!
Joel Berger

7

ความพยายามของฉันในการฮิวริสติกดังกล่าว (สมมติว่าคุณตัด ASCII และ UTF-8 ออกไป):

  • หาก 0x7f ถึง 0x9f ไม่ปรากฏขึ้นเลยอาจเป็น ISO-8859-1 เนื่องจากเป็นรหัสควบคุมที่ไม่ค่อยได้ใช้
  • หาก 0x91 ถึง 0x94 ปรากฏขึ้นที่จำนวนมากอาจเป็น Windows-1252 เนื่องจากเป็น "เครื่องหมายคำพูดอัจฉริยะ" ซึ่งเป็นอักขระที่เป็นไปได้มากที่สุดในช่วงนั้นที่จะใช้เป็นข้อความภาษาอังกฤษ เพื่อให้แน่ใจมากขึ้นคุณสามารถมองหาคู่
  • มิฉะนั้นจะเป็น MacRoman โดยเฉพาะอย่างยิ่งถ้าคุณเห็น 0xd2 ถึง 0xd5 จำนวนมาก (นั่นคือสิ่งที่คำพูดตัวพิมพ์อยู่ใน MacRoman)

หมายเหตุด้านข้าง:

สำหรับไฟล์เช่นซอร์ส Java ที่ไม่มีสิ่งอำนวยความสะดวกดังกล่าวอยู่ภายในไฟล์คุณจะต้องใส่การเข้ารหัสก่อนส่วนขยายเช่น SomeClass-utf8.java

อย่าทำอย่างนี้!!

คอมไพเลอร์ Java คาดว่าชื่อไฟล์จะตรงกับชื่อคลาสดังนั้นการเปลี่ยนชื่อไฟล์จะทำให้ซอร์สโค้ดไม่สามารถคอมไพล์ได้ สิ่งที่ถูกต้องจะเป็นที่จะคาดเดาการเข้ารหัสจากนั้นใช้native2asciiเครื่องมือในการแปลงอักขระที่ไม่ใช่ ASCII ทั้งหมดเพื่อUnicode ลำดับหนี


7
Stoopid kompilor! ไม่เราไม่สามารถบอกคนอื่นได้ว่าพวกเขาสามารถใช้ ASCII ได้เท่านั้น นี่ไม่ใช่ปี 1960 อีกต่อไป มันจะไม่มีปัญหาถ้ามีคำอธิบายประกอบ @encoding ดังนั้นความจริงที่ว่าซอร์สอยู่ในการเข้ารหัสเฉพาะไม่ได้ถูกบังคับให้เก็บไว้ภายนอกซอร์สโค้ดซึ่งเป็นข้อบกพร่องที่งี่เง่าของ Java ที่ทั้ง Perl และ Python ไม่ต้องทนทุกข์ทรมาน . มันควรจะอยู่ในแหล่ง นั่นไม่ใช่ปัญหาหลักของเรา มันเป็น*.textไฟล์มากกว่า1,000 ไฟล์
tchrist

3
@tchrist: จริง ๆ แล้วมันคงไม่ใช่เรื่องยากที่จะเขียนโปรเซสเซอร์คำอธิบายประกอบของคุณเองเพื่อรองรับคำอธิบายประกอบดังกล่าว ยังคงเป็นการกำกับดูแลที่น่าอับอายที่จะไม่ให้มีใน API มาตรฐาน
Michael Borgwardt

แม้ว่า Java ไม่สนับสนุน @encoding ที่จะไม่ให้แน่ใจว่าการประกาศการเข้ารหัสที่ถูกที่ถูกต้อง
dan04

4
@ dan04: คุณสามารถพูดเช่นเดียวกันเกี่ยวกับการประกาศการเข้ารหัสใน XML, HTML หรือที่อื่น ๆ แต่เช่นเดียวกับตัวอย่างเหล่านี้หากกำหนดไว้ใน Standard API เครื่องมือส่วนใหญ่ที่ทำงานกับซอร์สโค้ด (โดยเฉพาะบรรณาธิการและ IDE) จะรองรับซึ่งค่อนข้างน่าเชื่อถือป้องกันไม่ให้ผู้คนสร้างไฟล์โดยไม่ได้ตั้งใจซึ่งการเข้ารหัสของเนื้อหาไม่ตรงกัน Declartion
Michael Borgwardt

4
"คอมไพเลอร์ Java คาดว่าชื่อไฟล์จะตรงกับชื่อคลาส" กฎนี้ใช้เฉพาะในกรณีที่ไฟล์กำหนดคลาสสาธารณะระดับบนสุด
Matthew Flaschen

6

"Perl, C, Java หรือ Python และตามลำดับ": ทัศนคติที่น่าสนใจ :-)

"เรามีการเปลี่ยนแปลงที่ดีในการรู้ว่าบางสิ่งอาจเป็น UTF-8": จริงๆแล้วโอกาสที่ไฟล์ที่มีข้อความที่มีความหมายซึ่งเข้ารหัสในชุดอักขระอื่น ๆ ที่ใช้ไบต์ที่ตั้งค่าบิตสูงจะถอดรหัสสำเร็จเนื่องจาก UTF-8 มีขนาดเล็กลง

กลยุทธ์ UTF-8 (ในภาษาที่ต้องการน้อยที่สุด):

# 100% Unicode-standard-compliant UTF-8
def utf8_strict(text):
    try:
        text.decode('utf8')
        return True
    except UnicodeDecodeError:
        return False

# looking for almost all UTF-8 with some junk
def utf8_replace(text):
    utext = text.decode('utf8', 'replace')
    dodgy_count = utext.count(u'\uFFFD') 
    return dodgy_count, utext
    # further action depends on how large dodgy_count / float(len(utext)) is

# checking for UTF-8 structure but non-compliant
# e.g. encoded surrogates, not minimal length, more than 4 bytes:
# Can be done with a regex, if you need it

เมื่อคุณตัดสินใจแล้วว่าไม่ใช่ ASCII หรือ UTF-8:

เครื่องตรวจจับชาร์ตที่มาของ Mozilla ที่ฉันทราบว่าไม่รองรับ MacRoman และในกรณีใด ๆ ก็ไม่สามารถทำงานได้ดีกับชุดอักขระ 8 บิตโดยเฉพาะกับภาษาอังกฤษเนื่องจาก AFAICT ขึ้นอยู่กับการตรวจสอบว่าการถอดรหัสเหมาะสมหรือไม่ในสิ่งที่กำหนด ภาษาโดยไม่สนใจอักขระเครื่องหมายวรรคตอนและอิงตามเอกสารที่มีให้เลือกมากมายในภาษานั้น

อย่างที่คนอื่นตั้งข้อสังเกตคุณมีเฉพาะอักขระเครื่องหมายวรรคตอนที่กำหนดบิตสูงเท่านั้นที่สามารถแยกแยะระหว่าง cp1252 และ macroman ได้ ฉันขอแนะนำให้ฝึกโมเดล Mozilla ในเอกสารของคุณเองไม่ใช่ Shakespeare หรือ Hansard หรือ KJV Bible และคำนึงถึง 256 ไบต์ทั้งหมด ฉันคิดว่าไฟล์ของคุณไม่มีมาร์กอัป (HTML, XML และอื่น ๆ ) อยู่ในนั้นซึ่งจะบิดเบือนความน่าจะเป็นที่น่าตกใจ

คุณได้กล่าวถึงไฟล์ที่ส่วนใหญ่เป็น UTF-8 แต่ไม่สามารถถอดรหัสได้ คุณควรสงสัยอย่างมากเกี่ยวกับ:

(1) ไฟล์ที่ถูกกล่าวหาว่าเข้ารหัสใน ISO-8859-1 แต่มี "อักขระควบคุม" ในช่วง 0x80 ถึง 0x9F รวมอยู่ด้วย ... ซึ่งเป็นที่แพร่หลายมากจนมาตรฐาน HTML5 ฉบับร่างระบุว่าจะถอดรหัสสตรีม HTML ทั้งหมดที่ประกาศเป็น ISO-8859 -1 โดยใช้ cp1252

(2) ไฟล์ที่ถอดรหัส OK เป็น UTF-8 แต่ Unicode ที่เป็นผลลัพธ์มี "อักขระควบคุม" ในช่วง U + 0080 ถึง U + 009F รวมอยู่ด้วย ... ซึ่งอาจเป็นผลมาจากการแปลงรหัส cp1252 / cp850 (เห็นว่าเกิดขึ้น!) / ฯลฯ ไฟล์จาก "ISO-8859-1" ถึง UTF-8

ความเป็นมา: ฉันมีโครงการที่เปียก - วันอาทิตย์ - บ่ายเพื่อสร้างตัวตรวจจับชุดอักขระแบบ Python ที่เน้นไฟล์ (แทนที่จะเป็นแบบเว็บ) และทำงานได้ดีกับชุดอักขระ 8 บิตรวมถึงชุดlegacy ** nเช่น cp850 และ cp437 ใกล้เวลาไพรม์ไทม์แล้ว ฉันสนใจไฟล์การฝึกอบรม ไฟล์ ISO-8859-1 / cp1252 / MacRoman ของคุณนั้น "ไม่มีภาระผูกพัน" เท่า ๆ กันอย่างที่คุณคาดหวังว่าจะมีการแก้ปัญหาโค้ดของใครหรือไม่?


1
เหตุผลในการจัดลำดับภาษาคือสภาพแวดล้อม แอพพลิเคชั่นหลักส่วนใหญ่ของเรามักจะอยู่ใน java และยูทิลิตี้รองและแอพพลิเคชั่นบางตัวอยู่ใน perl เรามีโค้ดนิดหน่อยตรงนี้และมีอยู่ใน python ฉันส่วนใหญ่เป็นโปรแกรมเมอร์ C และ perl อย่างน้อยก็ด้วยตัวเลือกแรกดังนั้นฉันจึงมองหาโซลูชัน java เพื่อเสียบเข้ากับไลบรารีแอปของเราหรือไลบรารี perl สำหรับสิ่งเดียวกัน ถ้า C ฉันสามารถสร้างเลเยอร์กาว XS เพื่อเชื่อมต่อกับอินเทอร์เฟซ perl ได้ แต่ฉันไม่เคยทำใน python มาก่อน
tchrist

3

ดังที่คุณได้ค้นพบไม่มีวิธีใดที่สมบูรณ์แบบในการแก้ปัญหานี้เนื่องจากหากไม่มีความรู้โดยนัยเกี่ยวกับการเข้ารหัสไฟล์ที่ใช้การเข้ารหัส 8 บิตทั้งหมดจะเหมือนกันทุกประการ: ชุดของไบต์ ไบต์ทั้งหมดใช้ได้สำหรับการเข้ารหัส 8 บิตทั้งหมด

สิ่งที่ดีที่สุดที่คุณคาดหวังคืออัลกอริทึมบางประเภทที่วิเคราะห์ไบต์และขึ้นอยู่กับความน่าจะเป็นของไบต์ที่ใช้ในภาษาบางภาษาที่มีการเข้ารหัสบางอย่างจะคาดเดาได้ว่าการเข้ารหัสไฟล์ใช้อะไร แต่นั่นต้องรู้ว่าไฟล์ใช้ภาษาใดและจะไร้ประโยชน์โดยสิ้นเชิงเมื่อคุณมีไฟล์ที่มีการเข้ารหัสแบบผสม

ในทางกลับกันถ้าคุณรู้ว่าข้อความในไฟล์นั้นเขียนเป็นภาษาอังกฤษคุณจะไม่สังเกตเห็นความแตกต่างใด ๆ ไม่ว่าคุณจะใช้การเข้ารหัสแบบใดสำหรับไฟล์นั้นเนื่องจากความแตกต่างระหว่างการเข้ารหัสที่กล่าวถึงทั้งหมดจะถูกแปลเป็นภาษาท้องถิ่น ส่วนของการเข้ารหัสที่ระบุอักขระที่ปกติไม่ได้ใช้ในภาษาอังกฤษ คุณอาจมีปัญหาบางอย่างที่ข้อความใช้การจัดรูปแบบพิเศษหรือเครื่องหมายวรรคตอนเวอร์ชันพิเศษ (เช่น CP1252 มีอักขระเครื่องหมายคำพูดหลายเวอร์ชัน) แต่สำหรับส่วนสำคัญของข้อความอาจไม่มีปัญหา


1

หากคุณสามารถตรวจจับทุกการเข้ารหัส EXCEPT สำหรับ macroman มันเป็นเหตุผลที่จะถือว่าสิ่งที่ไม่สามารถถอดรหัสได้นั้นอยู่ใน macroman กล่าวอีกนัยหนึ่งเพียงแค่สร้างรายการไฟล์ที่ไม่สามารถประมวลผลได้และจัดการกับไฟล์เหล่านั้นราวกับว่าเป็นมนุษย์ขนาดเล็ก

อีกวิธีหนึ่งในการจัดเรียงไฟล์เหล่านี้คือการสร้างโปรแกรมบนเซิร์ฟเวอร์ที่ช่วยให้ผู้ใช้ตัดสินใจได้ว่าการเข้ารหัสใดที่ไม่อ่านไม่ออก แน่นอนว่ามันจะอยู่ใน บริษัท แต่ด้วยพนักงาน 100 คนที่ทำไม่กี่วันในแต่ละวันคุณจะมีไฟล์หลายพันไฟล์ในเวลาอันรวดเร็ว

สุดท้ายจะไม่เป็นการดีกว่าที่จะแปลงไฟล์ที่มีอยู่ทั้งหมดเป็นรูปแบบเดียวและต้องการให้ไฟล์ใหม่อยู่ในรูปแบบนั้น


5
ตลก! เมื่อฉันอ่านความคิดเห็นนี้เป็นครั้งแรกหลังจากถูกขัดจังหวะเป็นเวลา 30 นาทีฉันอ่าน "macroman" เป็น "มาโครแมน" และไม่ได้เชื่อมต่อกับ MacRoman จนกว่าฉันจะทำการค้นหาสตริงนั้นเพื่อดูว่า OP ได้กล่าวถึงหรือไม่
Adrian Pronk

+1 คำตอบนี้น่าสนใจมาก ไม่แน่ใจว่าเป็นความคิดที่ดีหรือไม่ดี ใครสามารถนึกถึงการเข้ารหัสที่มีอยู่ซึ่งอาจตรวจไม่พบ มีแนวโน้มที่จะมีในอนาคตหรือไม่?
ชื่อผู้ใช้

1

มีใครบ้างที่มีปัญหาเกี่ยวกับไฟล์ข้อความแบบดั้งเดิมที่เข้ารหัสแบบสุ่ม ถ้าเป็นเช่นนั้นคุณพยายามแก้ปัญหาอย่างไรและคุณประสบความสำเร็จเพียงใด

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

  1. กำหนดความน่าจะเป็นเริ่มต้น ( ก่อนหน้า ) ที่ไฟล์อยู่ในการเข้ารหัสโดยพิจารณาจากความถี่ของการเข้ารหัสแต่ละรายการ
  2. ตรวจสอบแต่ละไบต์ตามลำดับในไฟล์ ค้นหาค่าไบต์เพื่อพิจารณาความสัมพันธ์ระหว่างค่าไบต์ที่มีอยู่กับไฟล์ที่อยู่ในการเข้ารหัสนั้น ใช้ความสัมพันธ์นั้นเพื่อคำนวณความน่าจะเป็นใหม่ ( ด้านหลัง ) ที่ไฟล์อยู่ในการเข้ารหัส หากคุณมีไบต์ที่จะตรวจสอบมากขึ้นให้ใช้ความน่าจะเป็นหลังของไบต์นั้นเป็นความน่าจะเป็นก่อนหน้าเมื่อคุณตรวจสอบไบต์ถัดไป
  3. เมื่อคุณไปถึงจุดสิ้นสุดของไฟล์ (จริงๆแล้วฉันดูแค่ 1024 ไบต์แรกเท่านั้น) ความน่าจะเป็นที่คุณมีคือความน่าจะเป็นที่ไฟล์นั้นอยู่ในการเข้ารหัส

มันจะได้ว่า Bayes' ทฤษฎีบทกลายเป็นมากง่ายที่จะทำถ้าแทนของความน่าจะคำนวณคุณประมวลเนื้อหาข้อมูลซึ่งเป็นลอการิทึมของอัตราต่อรองinfo = log(p / (1.0 - p)) :

คุณจะต้องคำนวณค่าความน่าจะเป็นเริ่มต้นและความสัมพันธ์โดยการตรวจสอบคลังข้อมูลของไฟล์ที่คุณได้จัดประเภทด้วยตนเอง


1

การได้รับคำตอบที่ยอมรับhttps://stackoverflow.com/a/4200765/2731103ฉันสามารถปรับปรุงอัญมณีทับทิม "charlotte" เพื่อระบุการเข้ารหัสที่ร้องขอส่วนใหญ่ถูกต้อง

เราใช้สิ่งนั้นในสภาพแวดล้อมการผลิตเพื่อตรวจจับการเข้ารหัสไฟล์ CSV ก่อนนำเข้า

นั่นคือส่วนที่สมเหตุสมผล (Ruby)

UTF8HASBOM = /^\xEF\xBB\xBF/n      #  [239, 187, 191]
UTF32LEBOM = /^\xFF\xFE\x00\x00/n  # [255, 254, 0, 0]
UTF32BEBOM = /^\x00\x00\xFE\xFF/n  # [0, 0, 254, 255]

UTF16LEBOM = /^\xFF\xFE/n                # [255, 254]
UTF16BEBOM = /^\xFE\xFF/n                # [254, 255]

NOTIN1BYTE = /[\x00-\x06\x0B\x0E-\x1A\x1C-\x1F\x7F]/n
NOTISO8859 = /[\x00-\x06\x0B\x0E-\x1A\x1C-\x1F\x7F\x80-\x84\x86-\x9F]/n

# Information to identify MacRoman
# /programming/4198804/
NOTINCP1252 = /[\x81\x8D\x8F\x90\x9D]/n
CP1252CHARS = /[\x92\x95\x96\x97\xAE\xB0\xB7\xE8\xE9\xF6]/n
MCROMNCHARS = /[\x8E\x8F\x9A\xA1\xA5\xA8\xD0\xD1\xD5\xE1]/n
detect.force_encoding('BINARY') # Needed to prevent non-matching regex charset.
sample = detect[0..19]     # Keep sample string under 23 bytes.
detect.sub!(UTF8HASBOM, '') if sample[UTF8HASBOM] # Strip any UTF-8 BOM.

# See: http://www.daniellesucher.com/2013/07/23/ruby-case-versus-if/
if    sample.ascii_only? && detect.force_encoding('UTF-8').valid_encoding?

elsif sample[UTF32LEBOM] && detect.force_encoding('UTF-32LE').valid_encoding?
elsif sample[UTF32BEBOM] && detect.force_encoding('UTF-32BE').valid_encoding?
elsif sample[UTF16LEBOM] && detect.force_encoding('UTF-16LE').valid_encoding?
elsif sample[UTF16BEBOM] && detect.force_encoding('UTF-16BE').valid_encoding?

elsif detect.force_encoding('UTF-8').valid_encoding?

elsif detect.force_encoding('BINARY')[NOTISO8859].nil?
  detect.force_encoding('ISO-8859-1')

elsif detect.force_encoding('BINARY')[NOTIN1BYTE].nil?

  if  detect.force_encoding('BINARY')[NOTINCP1252].nil? &&
            detect.force_encoding('BINARY').scan(MCROMNCHARS).length < detect.force_encoding('BINARY').scan(CP1252CHARS).length

      detect.force_encoding('Windows-1252')
  else
      detect.force_encoding('MacRoman')
  end

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