UnicodeEncodeError: ตัวแปลงสัญญาณ 'ascii' ไม่สามารถเข้ารหัสอักขระ u '\ xa0' ในตำแหน่ง 20: ลำดับไม่อยู่ในช่วง (128)


1296

ฉันมีปัญหาในการจัดการกับอักขระ Unicode จากข้อความที่ดึงมาจากหน้าเว็บต่างๆ (ในเว็บไซต์ต่าง ๆ ) ฉันใช้ BeautifulSoup

ปัญหาคือข้อผิดพลาดนั้นไม่สามารถทำซ้ำได้เสมอไป บางครั้งมันก็ทำงานร่วมกับบางหน้าและบางครั้งก็ barfs UnicodeEncodeErrorโดยขว้างปา ฉันลองทุกอย่างที่ฉันสามารถคิดได้ แต่ถึงกระนั้นฉันก็ไม่พบสิ่งใดที่ทำงานได้อย่างต่อเนื่องโดยไม่ละทิ้งข้อผิดพลาดที่เกี่ยวข้องกับ Unicode

ส่วนหนึ่งของรหัสที่ทำให้เกิดปัญหาแสดงอยู่ด้านล่าง:

agent_telno = agent.find('div', 'agent_contact_number')
agent_telno = '' if agent_telno is None else agent_telno.contents[0]
p.agent_info = str(agent_contact + ' ' + agent_telno).strip()

นี่คือการติดตามสแต็กที่สร้างบนสตริง SOME เมื่อรันโค้ดย่อยด้านบน:

Traceback (most recent call last):
  File "foobar.py", line 792, in <module>
    p.agent_info = str(agent_contact + ' ' + agent_telno).strip()
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 20: ordinal not in range(128)

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

ใครบ้างมีความคิดเกี่ยวกับวิธีการแก้ปัญหานี้เพื่อให้ฉันสามารถแก้ไขปัญหานี้อย่างต่อเนื่อง?


1
หากคุณได้รับข้อผิดพลาดเหล่านี้ในฐานะผู้ใช้แทนที่จะเป็นนักพัฒนาตรวจสอบserverfault.com/questions/54591/ …และaskubuntu.com/questions/599808/ …
คนบราซิลนั่น

ฉันจะเพิ่มจุดนี้ไม่ได้ใช้onlinegdb.com/online_python_interpreterสำหรับสิ่งนี้ ใช้ล่ามนั้นในการทดลองใช้และไม่ได้กำหนดค่าอย่างถูกต้องสำหรับ Unicode! เคยพิมพ์ในรูปแบบ 'B' \ nnn '' ... เมื่อทั้งหมดที่ฉันต้องการคือ guillemet! ลองใช้ VM และทำงานได้ทันทีตามที่คาดไว้โดยใช้ chr ()
JGFMK

4
import os; import locale; os.environ["PYTHONIOENCODING"] = "utf-8"; myLocale=locale.setlocale(category=locale.LC_ALL, locale="en_GB.UTF-8"); ... print(myText.encode('utf-8', errors='ignore'))ลองนี้
hhh

@hhh ฉันวิ่งตัวอย่างโค้ด NameError ของคุณ: ไม่ได้กำหนดชื่อ 'myText'
KHAN irfan

9
ลองตั้งPYTHONIOENCODINGในเชลล์ก่อนที่จะประมวลผลสคริปต์ของคุณ:$ export PYTHONIOENCODING=utf8
Noam Manos

คำตอบ:


1361

คุณจะต้องอ่านหลามHOWTO Unicode ข้อผิดพลาดนี้เป็นตัวอย่างแรกมาก

โดยทั่วไปให้หยุดใช้strเพื่อแปลงจากยูนิโคดเป็นข้อความ / ไบต์ที่เข้ารหัส

ให้ใช้.encode()การเข้ารหัสสตริงอย่างถูกต้องแทน:

p.agent_info = u' '.join((agent_contact, agent_telno)).encode('utf-8').strip()

หรือทำงานทั้งหมดในยูนิโค้ด


23
ตกลงกัน! กฎง่ายๆที่ฉันได้รับการสอนคือการใช้แนวคิด "Unicode Sandwich" สคริปต์ของคุณยอมรับไบต์จากโลกภายนอก แต่การประมวลผลทั้งหมดควรทำในยูนิโค้ด เมื่อคุณพร้อมที่จะส่งออกข้อมูลของคุณก็ควรที่จะถูกย้อนกลับเป็นไบต์!
Andbdrew

256
ในกรณีที่คนอื่นสับสนโดยนี้ฉันพบสิ่งที่แปลก: terminal ของฉันใช้ utf-8 และเมื่อฉันprintutf-8 ของฉันมันทำงานได้ดี UnicodeEncodeErrorแต่เมื่อฉันท่อโปรแกรมการส่งออกของฉันไปยังแฟ้มมันพ่น ในความเป็นจริงเมื่อผลลัพธ์ถูกเปลี่ยนเส้นทาง (ไปยังไฟล์หรือไปป์) ฉันพบว่าsys.stdout.encodingเป็นNone! การ.encode('utf-8')แก้ไขปัญหา
drevicko

93
@drevicko: ใช้PYTHONIOENCODING=utf-8แทนเช่นพิมพ์ Unicode strings และปล่อยให้สิ่งแวดล้อมตั้งค่าการเข้ารหัสที่คาดไว้
jfs

1
@steinar: ไม่มีอะไรถูกต้องในทุกกรณี โดยทั่วไปผู้ใช้ไม่ควรสนใจว่าคุณใช้ Python ในการใช้ยูทิลิตี้ของคุณ (อินเทอร์เฟซไม่ควรเปลี่ยนแปลงหากคุณตัดสินใจที่จะนำมันไปใช้ในภาษาอื่นด้วยเหตุผลใดก็ตาม) ดังนั้นคุณไม่ควรคาดหวังว่าผู้ใช้ envvars เฉพาะ UI ไม่ดีที่จะบังคับให้ผู้ใช้ระบุการเข้ารหัสอักขระ ฝังการเข้ารหัสอักขระในรูปแบบรายงานหากจำเป็น หมายเหตุ: การเข้ารหัสแบบฮาร์ดโค้ดไม่สามารถเป็น "ค่าเริ่มต้นที่สมเหตุสมผล" ในกรณีทั่วไป
jfs

13
นี่เป็นคำแนะนำที่ไม่ดีและสับสน เหตุผลที่คนใช้ str เป็นเพราะวัตถุยังไม่ได้เป็นสตริงดังนั้นจึงไม่มี.encode()วิธีการโทร
Cerin

433

นี่คือจุดปวดงูหลาม Unicode คลาสสิก! พิจารณาสิ่งต่อไปนี้:

a = u'bats\u00E0'
print a
 => batsà

ดีมากจนถึงตอนนี้ แต่ถ้าเราโทรหา str (a) เรามาดูกันว่าเกิดอะไรขึ้น:

str(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)

โอ้จิ้มนั่นจะไม่ทำให้ใครดีเลย! ในการแก้ไขข้อผิดพลาดให้เข้ารหัสไบต์อย่างชัดเจนด้วย. encode และบอก python ว่าตัวแปลงสัญญาณที่ใช้:

a.encode('utf-8')
 => 'bats\xc3\xa0'
print a.encode('utf-8')
 => batsà

Voil \ u00E0!

ปัญหาคือเมื่อคุณโทรหา str () ไพ ธ อนใช้การเข้ารหัสตัวอักษรเริ่มต้นเพื่อลองและเข้ารหัสไบต์ที่คุณให้ไว้ ในการแก้ไขปัญหาคุณต้องบอก python วิธีจัดการกับสตริงที่คุณให้โดยใช้. encode ('Anything_unicode') เวลาส่วนใหญ่คุณควรใช้ utf-8

สำหรับการอธิบายอย่างยอดเยี่ยมในหัวข้อนี้โปรดดูการพูดคุยเรื่อง PyCon ของ Ned Batchelder ที่นี่: http://nedbatchelder.com/text/unipain.html


85
บันทึกส่วนตัว: เมื่อพยายามพิมพ์ ".encode" อย่าพิมพ์โดยไม่ตั้งใจ ". unicode" แล้วสงสัยว่าทำไมไม่มีอะไรทำงาน
ข้าม Huffman

9
คำปรึกษาที่ดี. แต่คุณจะทำอย่างไรเมื่อคุณใช้ str (x) เพื่อพิมพ์วัตถุที่อาจจะใช่หรือไม่ใช่สตริง? str (x) ทำงานถ้า x เป็นตัวเลขเวลาวันที่บูลีนหรือสตริงปกติ ทันใดนั้นถ้ามันเป็นยูนิโค้ดมันก็หยุดทำงาน มีวิธีที่จะได้รับพฤติกรรมเดียวกันหรือตอนนี้เราจำเป็นต้องเพิ่มการตรวจสอบ IF เพื่อทดสอบว่าวัตถุเป็นสตริงที่จะใช้. encode และ str () มิฉะนั้น?
เดิร์กอาร์

คำถามเดียวกันสามารถถามด้วยNoneค่า
Vadorequest

210

ฉันพบว่าการทำงานที่หรูหราสำหรับฉันที่จะลบสัญลักษณ์และทำให้สตริงเป็นสตริงต่อไปนี้:

yourstring = yourstring.encode('ascii', 'ignore').decode('ascii')

สิ่งสำคัญคือให้สังเกตว่าการใช้ตัวเลือกการเพิกเฉยเป็นสิ่งที่อันตรายเพราะมันจะลดการสนับสนุน unicode (และการทำให้เป็นสากล) จากโค้ดที่ใช้งานแบบเงียบ ๆ ดังที่เห็นที่นี่ (แปลง unicode):

>>> u'City: Malmö'.encode('ascii', 'ignore').decode('ascii')
'City: Malm'

17
คุณทำวันของฉัน! สำหรับ utf-8 ก็เพียงพอแล้วที่จะทำ:yourstring = yourstring.encode('utf-8', 'ignore').decode('utf-8')
luca76

สำหรับฉันนี่ใช้งานได้ แต่กรณีของฉันแตกต่างกันฉันบันทึกชื่อไฟล์และมี "/" ในชื่อและพา ธ ไม่มีอยู่ดังนั้นฉันจึงต้องใช้. แทนที่ ("/", "") ดังนั้นจึงบันทึก สคริปต์ของฉัน ในขณะที่ไม่สนใจ ASCII ก็สามารถใช้ได้กับเคส 'utf-8' ด้วย
Akash Kandpal

1
@ harrypotter0 สำหรับการเชื่อมพา ธ ไฟล์ที่ถูกต้องใช้os.path.join()มันเป็นนิสัยที่ดีมากเมื่อคุณเริ่มทำการเขียนโปรแกรมข้ามแพลตฟอร์ม :)
login_not_failed

152

ดีฉันพยายามทุกอย่าง แต่มันก็ไม่ได้ช่วยหลังจาก googling รอบ ๆ ฉันคิดต่อไปนี้และมันช่วย python 2.7 ถูกใช้งานอยู่

# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')

7
อย่าทำอย่างนี้ stackoverflow.com/questions/3828723/…แม้ว่าเมื่อคุณมีคำตอบเช่นstackoverflow.com/a/31137935/2141635ใกล้ด้านบนของผลลัพธ์เมื่อคุณค้นหาข้อผิดพลาดฉันสามารถดูสาเหตุที่อาจเป็นความคิดที่ดี
Padraic Cunningham

21
ฉันลองคำแนะนำเกือบทั้งหมดในหัวข้อนี้และไม่มีใครทำงานให้ฉันได้ ในที่สุดฉันก็ลองอันนี้ และมันก็เป็นสิ่งเดียวที่ทำงานได้ง่ายและดี ถ้ามีคนพูดว่า "อย่าทำอย่างนั้นมาพร้อมกับ Solution ง่ายๆมิฉะนั้นใช้อันนี้เพราะมันเป็นสำเนาที่ใช้งานได้ดี
Richard de Ree

4
วิธีนี้สามารถทำได้ใน python3 ยินดีที่จะรู้
Kanerva Peter

3
หลังจากแห้วมากนี้ทำงาน ขอบคุณมัด
Avraham Zhurba

4
ฉันเพิ่งจะเพิ่มif sys.version_info.major < 3:
ศ. สัญญา Falken ละเมิด

87

ปัญหาเล็ก ๆ น้อย ๆ ที่ทำให้เกิดการพิมพ์แม้กระทั่งล้มเหลวก็คือการตั้งค่าตัวแปรสภาพแวดล้อมของคุณผิด ที่นี่ LC_ALL ตั้งค่าเป็น "C" ใน Debian พวกเขาไม่สนับสนุนการตั้งค่า: Debian wiki บน Locale

$ echo $LANG
en_US.utf8
$ echo $LC_ALL 
C
$ python -c "print (u'voil\u00e0')"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)
$ export LC_ALL='en_US.utf8'
$ python -c "print (u'voil\u00e0')"
voilà
$ unset LC_ALL
$ python -c "print (u'voil\u00e0')"
voilà

มีปัญหาเดียวกันว่าไม่ดีดังนั้นผมจึงไม่ได้ตรวจสอบก่อนที่จะรายงาน ขอบคุณมาก. env|grep -E '(LC|LANG)'โดยวิธีการที่คุณสามารถแทนที่ทั้งสองคำสั่งครั้งแรกกับ
Dmitry Verhoturov

แค่สองเซ็นต์ของฉันกับปัญหาการเข้ารหัสผิด ฉันมักใช้mcในโหมด "subshell" ( Ctrl-O) alias mc="LANG=en_EN.UTF-8 mc"และฉันยังลืมไปว่าผมเพิ่มนามแฝงต่อไปนี้เพื่อทุบตี: ดังนั้นเมื่อฉันพยายามเรียกใช้สคริปต์ที่เขียนไม่ดีซึ่งต้องพึ่งพาru_RU.UTF-8ภายในพวกเขาจะตาย พยายามหลายสิ่งจากเธรดนี้ก่อนที่ฉันจะค้นพบปัญหาจริง :)
login_not_failed

คุณน่ากลัว ใน GSUTIL rsync ของฉันล้มเหลวเนื่องจากปัญหานี้ แก้ไข LC_ALL และทุกอย่างทำงานได้ดีเหมือนไวน์ <3 ขอบคุณ <3
dsignr

27

สำหรับฉันสิ่งที่ทำงานคือ:

BeautifulSoup(html_text,from_encoding="utf-8")

หวังว่านี่จะช่วยใครซักคน


25

ฉันได้พบว่าจริง ๆ แล้วในกรณีส่วนใหญ่ของฉันเพียงแค่แยกตัวละครเหล่านั้นออกจะง่ายกว่ามาก

s = mystring.decode('ascii', 'ignore')

26
"สมบูรณ์แบบ" มักจะไม่ได้ประสิทธิภาพ มันทิ้งสิ่งที่คุณควรรู้วิธีจัดการกับอย่างถูกต้อง
tripleee

7
การถอดตัวอักษร "ที่ไม่ใช่ภาษาอังกฤษ" ออกไม่ใช่วิธีแก้ปัญหาเนื่องจากงูใหญ่ต้องรองรับทุกภาษาที่คุณไม่คิด?
alemol

8
downvoted นี่ไม่ใช่ทางออกที่ถูกต้องเลย เรียนรู้วิธีทำงานกับ Unicode: joelonsoftware.com/articles/Unicode.html
Andrew Ferrier

4
ดูวิธีที่ฉลาดที่สุดในการนำเสนอคำตอบนี้คือด้วยวิธีนี้: การรับรู้ว่า ASCII ได้รับสิทธิพิเศษบางอย่างในภาษาและผู้ใช้บางราย - นี่คือช่องทางหลบหนีที่อาจถูกเอารัดเอาเปรียบสำหรับผู้ใช้ที่อาจแฮ็คคร่าวๆ สคริปต์ด้วยกันอาจทำงานเบื้องต้นได้ก่อนที่จะมีการสนับสนุน Unicode แบบเต็ม
lol

5
หากฉันเขียนสคริปต์ที่ต้องการพิมพ์ข้อความภาษาอังกฤษเป็น stdout ในแอปพลิเคชันภายใน บริษัท ฉันแค่ต้องการให้ปัญหาหายไป อะไรก็ตามที่ใช้งานได้
kagronick

25

ปัญหาคือคุณพยายามพิมพ์อักขระ Unicode แต่เทอร์มินัลของคุณไม่รองรับ

คุณสามารถลองติดตั้งlanguage-pack-enแพ็กเกจเพื่อแก้ไข:

sudo apt-get install language-pack-en

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

ในลีนุกซ์บางรุ่นจำเป็นต้องมีการตั้งค่าภาษาอังกฤษเริ่มต้นให้ถูกต้อง (เพื่อให้สามารถจัดการอักขระยูนิโค้ดได้โดยเชลล์ / เทอร์มินัล) บางครั้งการติดตั้งง่ายกว่าการกำหนดค่าด้วยตนเอง

จากนั้นเมื่อเขียนรหัสตรวจสอบให้แน่ใจว่าคุณใช้การเข้ารหัสที่ถูกต้องในรหัสของคุณ

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

open(foo, encoding='utf-8')

หากคุณยังคงมีปัญหาให้ตรวจสอบการกำหนดค่าระบบของคุณอีกครั้งเช่น:

  • ไฟล์ภาษาของคุณ ( /etc/default/locale) ซึ่งควรมีเช่น

    LANG="en_US.UTF-8"
    LC_ALL="en_US.UTF-8"

    หรือ:

    LC_ALL=C.UTF-8
    LANG=C.UTF-8
  • ค่าของLANG/ LC_CTYPEในเชลล์

  • ตรวจสอบว่าเชลล์ของคุณรองรับตำแหน่งใด:

    locale -a | grep "UTF-8"

แสดงให้เห็นถึงปัญหาและแนวทางแก้ไขใน VM ใหม่

  1. เริ่มต้นและจัดเตรียม VM (เช่นใช้vagrant):

    vagrant init ubuntu/trusty64; vagrant up; vagrant ssh

    ดู: กล่อง Ubuntu ใช้ได้ .

  2. การพิมพ์อักขระ Unicode (เช่นเครื่องหมายการค้าที่ชอบ):

    $ python -c 'print(u"\u2122");'
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
    UnicodeEncodeError: 'ascii' codec can't encode character u'\u2122' in position 0: ordinal not in range(128)
  3. กำลังติดตั้งlanguage-pack-en:

    $ sudo apt-get -y install language-pack-en
    The following extra packages will be installed:
      language-pack-en-base
    Generating locales...
      en_GB.UTF-8... /usr/sbin/locale-gen: done
    Generation complete.
  4. ตอนนี้ปัญหาควรได้รับการแก้ไข:

    $ python -c 'print(u"\u2122");'
    
  5. มิฉะนั้นลองคำสั่งต่อไปนี้:

    $ LC_ALL=C.UTF-8 python -c 'print(u"\u2122");'
    

1
สิ่งที่ได้language-pack-enมีการทำกับงูหลามหรือคำถามนี้หรือไม่? AFAIK อาจให้บริการแปลภาษาเป็นข้อความ แต่ไม่มีส่วนเกี่ยวข้องกับการเข้ารหัส
Alastair McCormack

2
ในลีนุกซ์รุ่นลีนุกซ์บางรุ่นจำเป็นต้องมีการตั้งค่าภาษาอังกฤษให้ถูกต้องโดยเฉพาะอย่างยิ่งเมื่อรันสคริปต์ Python บนเทอร์มินัล มันได้ผลสำหรับฉัน ณ จุดหนึ่ง โปรดดู: การเข้ารหัสอักขระ
kenorb

อาโอเค. คุณหมายถึงถ้าคุณต้องการใช้ภาษาที่ไม่ใช่ภาษาอังกฤษ? ฉันเดาว่าผู้ใช้จะต้องแก้ไข/etc/locale.genเพื่อให้มั่นใจว่าสถานที่ของพวกเขาถูกสร้างขึ้นก่อนใช้งานหรือไม่
Alastair McCormack

1
@AlastairMcCormack แสดงความคิดเห็นLANGจาก/etc/default/locale( /etc/locale.genไม่มีอยู่) และวิ่งlocale-genแต่มันก็ไม่ได้ช่วย ฉันไม่แน่ใจว่าทำสิ่งใดlanguage-pack-enอย่างถูกต้องเพราะฉันไม่พบเอกสารจำนวนมากและการแสดงเนื้อหาของมันไม่ได้ช่วยอะไรมาก
kenorb

1
ไม่น่าเป็นไปได้ที่จะไม่มีโลแคล utf-8 ในระบบเดสก์ท็อปอยู่แล้วนั่นเป็นไปได้ว่าคุณไม่จำเป็นต้องติดตั้งอะไรเลยเพียงแค่กำหนดค่าLANG/ LC_CTYPE/ LC_ALLแทน (เช่นLANG=C.UTF-8)
jfs

19

ในเปลือก:

  1. ค้นหาโลแคล UTF-8 ที่รองรับโดยคำสั่งต่อไปนี้:

    locale -a | grep "UTF-8"
  2. ส่งออกก่อนที่จะรันสคริปต์เช่น:

    export LC_ALL=$(locale -a | grep UTF-8)

    หรือชอบ:

    export LC_ALL=C.UTF-8
  3. ทดสอบด้วยการพิมพ์อักขระพิเศษเช่น:

    python -c 'print(u"\u2122");'

ผ่านการทดสอบใน Ubuntu


ใช่นี่เป็นคำตอบสั้น ๆ ที่ดีที่สุดเราไม่สามารถแก้ไขซอร์สโค้ดเพื่อใช้. รหัส
Luat Nguyen - Neo.Mxn0

16

เพิ่มบรรทัดด้านล่างที่จุดเริ่มต้นของสคริปต์ของคุณ (หรือเป็นบรรทัดที่สอง):

# -*- coding: utf-8 -*-

นั่นเป็นคำจำกัดความของการเข้ารหัสรหัสไพ ธ อน ข้อมูลอื่น ๆ ในPEP 263


2
สิ่งนี้ไม่ได้แก้ปัญหาเมื่อข้อความที่ประมวลผลโหลดจากไฟล์ภายนอกมีการเข้ารหัส utf-8 สิ่งนี้จะช่วยเฉพาะสำหรับตัวอักษรที่เขียนในสคริปต์ไพ ธ อนที่กำหนดเองและเป็นเพียงคำใบ้สำหรับล่ามไพ ธ อน แต่ไม่มีผลต่อการประมวลผลข้อความ
Mikaelblomkvistsson

16

ต่อไปนี้เป็นคำตอบที่เรียกว่า "cop out" อื่น ๆ มีสถานการณ์ที่การทิ้งตัวละคร / สายอักขระที่มีปัญหานั้นเป็นทางออกที่ดีแม้จะมีการประท้วงที่เปล่งออกมาที่นี่

def safeStr(obj):
    try: return str(obj)
    except UnicodeEncodeError:
        return obj.encode('ascii', 'ignore').decode('ascii')
    except: return ""

ทดสอบมัน:

if __name__ == '__main__': 
    print safeStr( 1 ) 
    print safeStr( "test" ) 
    print u'98\xb0'
    print safeStr( u'98\xb0' )

ผล:

1
test
98°
98

คำแนะนำ: คุณอาจต้องการตั้งชื่อฟังก์ชั่นนี้toAsciiแทน นั่นเป็นเรื่องของการตั้งค่า

นี้ถูกเขียนขึ้นสำหรับหลาม 2. สำหรับหลาม 3 ผมเชื่อว่าคุณจะต้องการใช้มากกว่าbytes(obj,"ascii") str(obj)ฉันยังไม่ได้ทดสอบสิ่งนี้ แต่ในบางครั้งฉันจะแก้ไขคำตอบ


8

ฉันมักจะใส่รหัสด้านล่างในสองบรรทัดแรกของไฟล์หลาม:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

6

ฟังก์ชั่นช่วยที่ง่ายพบได้ที่นี่

def safe_unicode(obj, *args):
    """ return the unicode representation of obj """
    try:
        return unicode(obj, *args)
    except UnicodeDecodeError:
        # obj is byte string
        ascii_text = str(obj).encode('string_escape')
        return unicode(ascii_text)

def safe_str(obj):
    """ return the byte string representation of obj """
    try:
        return str(obj)
    except UnicodeEncodeError:
        # obj is unicode
        return unicode(obj).encode('unicode_escape')

เพื่อให้ได้หนี bytestring (การแปลงสายอักขระ Unicode พลไบต์โดยใช้การเข้ารหัส ASCII), คุณสามารถใช้จัดการข้อผิดพลาด:backslashreplace u'\xa0'.encode('ascii', 'backslashreplace')แม้ว่าคุณควรหลีกเลี่ยงการเป็นตัวแทนดังกล่าวและกำหนดค่าสภาพแวดล้อมของคุณให้ยอมรับอักขระที่ไม่ใช่ ASCII แทน - นั่นคือ 2016!
jfs

สวัสดีปีใหม่ @JFSebastian ฉันเพิ่งผิดหวังกับปัญหา Python-Unicode และในที่สุดก็ได้โซลูชันนี้ซึ่งใช้งานได้ ฉันไม่รู้เกี่ยวกับสิ่งนี้ อย่างไรก็ตามขอขอบคุณสำหรับเคล็ดลับ
Parag Tyagi -morpheus-



3

ฉันเพิ่งใช้สิ่งต่อไปนี้:

import unicodedata
message = unicodedata.normalize("NFKD", message)

ตรวจสอบสิ่งที่เอกสารพูดเกี่ยวกับมัน:

unicodedata.normalize (ฟอร์ม unistr) ส่งคืนฟอร์มฟอร์มปกติสำหรับ unistrode Unicode string ค่าที่ถูกต้องสำหรับฟอร์มคือ 'NFC', 'NFKC', 'NFD' และ 'NFKD'

มาตรฐาน Unicode กำหนดรูปแบบการนอร์มัลไลซ์ต่าง ๆ ของสายอักขระ Unicode ตามคำจำกัดความของการเทียบเท่าแบบบัญญัติและความเข้ากันได้ที่เทียบเท่า ใน Unicode อักขระหลายตัวสามารถแสดงได้หลายวิธี ตัวอย่างเช่นตัวละคร U + 00C7 (ตัวอักษรละตินทุน C กับ CEDILLA) สามารถแสดงเป็นลำดับ U + 0043 (ตัวอักษรละตินทุน C) U + 0327 (CEDILLA รวม)

สำหรับอักขระแต่ละตัวมีสองรูปแบบปกติ: รูปแบบปกติ C และรูปแบบปกติ D รูปแบบปกติ D (NFD) ยังเป็นที่รู้จักกันในนามการสลายตัวที่ยอมรับและแปลตัวละครแต่ละตัวในรูปแบบย่อยสลายของมัน รูปแบบปกติ C (NFC) ใช้การสลายตัวแบบบัญญัติก่อนแล้วจึงรวมอักขระที่รวมกันอีกครั้ง

นอกเหนือจากสองรูปแบบเหล่านี้แล้วยังมีอีกสองรูปแบบปกติตามความเข้ากันได้ที่เทียบเท่า ใน Unicode สนับสนุนอักขระบางตัวซึ่งโดยทั่วไปจะรวมกับอักขระอื่น ตัวอย่างเช่น U + 2160 (ตัวเลขโรมันหนึ่ง) เป็นสิ่งเดียวกับ U + 0049 (ทุนละตินอักษร I) อย่างไรก็ตามได้รับการสนับสนุนใน Unicode สำหรับความเข้ากันได้กับชุดอักขระที่มีอยู่ (เช่น gb2312)

KD (NFKD) รูปแบบปกติจะใช้การสลายตัวของความเข้ากันได้เช่นแทนที่อักขระที่เข้ากันได้ทั้งหมดด้วยสิ่งที่เทียบเท่า รูปแบบปกติ KC (NFKC) ก่อนใช้การสลายตัวที่เข้ากันได้ตามด้วยองค์ประกอบบัญญัติ

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

แก้เพื่อฉัน ง่ายและสะดวก


3

วิธีแก้ปัญหาด้านล่างใช้ได้สำหรับฉันเพิ่งเพิ่ม

คุณ "String"

(แทนสตริงเป็นยูนิโค้ด) ต่อหน้าสตริงของฉัน

result_html = result.to_html(col_space=1, index=False, justify={'right'})

text = u"""
<html>
<body>
<p>
Hello all, <br>
<br>
Here's weekly summary report.  Let me know if you have any questions. <br>
<br>
Data Summary <br>
<br>
<br>
{0}
</p>
<p>Thanks,</p>
<p>Data Team</p>
</body></html>
""".format(result_html)

3

อนิจจาสิ่งนี้ใช้ได้ใน Python 3 อย่างน้อย ...

Python 3

บางครั้งข้อผิดพลาดอยู่ในตัวแปรสภาพแวดล้อมและการเข้ารหัสเช่นนั้น

import os
import locale
os.environ["PYTHONIOENCODING"] = "utf-8"
myLocale=locale.setlocale(category=locale.LC_ALL, locale="en_GB.UTF-8")
... 
print(myText.encode('utf-8', errors='ignore'))

โดยที่ข้อผิดพลาดถูกละเว้นในการเข้ารหัส


2

ฉันเพิ่งมีปัญหานี้และ Google ก็พาฉันมาที่นี่ดังนั้นเพียงเพิ่มโซลูชันทั่วไปที่นี่นี่คือสิ่งที่ใช้ได้กับฉัน:

# 'value' contains the problematic data
unic = u''
unic += value
value = unic

ฉันมีความคิดนี้หลังจากที่ได้อ่านงานนำเสนอของเน็ด

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


3
อะไรคือสิ่งที่typeมีค่า? ก่อนและหลังนี้ ผมคิดว่าทำไมผลงานที่เป็นที่ด้วยการทำunic += valueซึ่งเป็นเช่นเดียวกับunic = unic + valueคุณกำลังเพิ่มสตริงและ Unicode ที่หลามแล้วถือว่า Unicode สำหรับผลลัพธ์unicคือประเภทที่แม่นยำยิ่งขึ้น (คิดว่าเมื่อคุณทำเช่นนี้a = float(1) + int(1), aจะกลายเป็น float) และ จากนั้นvalue = unicชี้valueไปที่unicวัตถุใหม่ซึ่งเกิดเป็นยูนิโค้ด
Tom Myddeltyn

2

เราพบข้อผิดพลาดนี้เมื่อทำงานmanage.py migrateใน Django ด้วยการแข่งขันที่มีการแปล

แหล่งที่มาของเรามีการ# -*- coding: utf-8 -*-ประกาศ MySQL ถูกกำหนดค่าอย่างถูกต้องสำหรับ utf8 และ Ubuntu มีชุดภาษาและค่าที่/etc/default/localeเหมาะสม

ปัญหาคือว่าภาชนะ Django (เราใช้นักเทียบท่า) หายไปLANGenv var

การตั้งค่าLANGการen_US.UTF-8และรีสตาร์ทภาชนะก่อนการโยกย้ายอีกครั้งการทำงานแก้ไขปัญหา


1

คำตอบมากมายที่นี่ (เช่น @agf และ @Andbdrew) ได้กล่าวถึงประเด็นที่รวดเร็วที่สุดของคำถาม OP แล้ว

อย่างไรก็ตามฉันคิดว่ามันมีแง่มุมที่สำคัญ แต่สำคัญที่ถูกเพิกเฉยและสำคัญสำหรับทุกคนที่ชอบฉันที่นี่ในขณะที่พยายามทำความเข้าใจการเข้ารหัสใน Python: Python 2 กับ Python 3 การจัดการการแสดงตัวละครนั้นแตกต่างกันอย่างสิ้นเชิง . ฉันรู้สึกว่ามีความสับสนเกิดขึ้นกับผู้คนที่อ่านเกี่ยวกับการเข้ารหัสใน Python โดยไม่ทราบถึงเวอร์ชัน

ฉันขอแนะนำให้ทุกคนที่สนใจในการทำความเข้าใจสาเหตุของปัญหา OP เพื่อเริ่มต้นด้วยการอ่านบทนำของ Spolskyเกี่ยวกับการแสดงตัวละครและ Unicode แล้วย้ายไปที่Batchelderบน Unicode ใน Python 2 และ Python 3


ใช่ข้อผิดพลาดของฉันคือ python 2.7, 'a'.format (u'ñ') และวิธีแก้ไขที่ถูกต้องคือไม่ใช้. encode ('utf-8') แต่ใช้สตริง unicode เสมอ (ค่าเริ่มต้นใน python 3 ): u'a'.format (u'ñ '),
Rogelio

1

พยายามหลีกเลี่ยงการแปลงตัวแปรเป็น str (ตัวแปร) บางครั้งอาจทำให้เกิดปัญหา

เคล็ดลับง่ายๆที่ควรหลีกเลี่ยง:

try: 
    data=str(data)
except:
    data = data #Don't convert to String

ตัวอย่างข้างต้นจะแก้ไขข้อผิดพลาด Encode ด้วย


สิ่งนี้ไม่ทำงานตามที่คุณเพิ่งพบข้อผิดพลาดในยกเว้น
Aurele Collinet


0

อัพเดตสำหรับ python 3.0 และใหม่กว่า ลองสิ่งต่อไปนี้ในเครื่องมือแก้ไขหลาม:

locale-gen en_US.UTF-8
export LANG=en_US.UTF-8 LANGUAGE=en_US.en
LC_ALL=en_US.UTF-8

นี่เป็นการตั้งค่าโลแคลเริ่มต้นของระบบเป็นรูปแบบ UTF-8

เพิ่มเติมสามารถอ่านได้ที่นี่ที่ PEP 538 - บีบบังคับสถานที่มรดก C ถึงสถานที่เกิดเหตุ


0

ฉันมีปัญหานี้พยายามส่งออกอักขระ Unicode ไปstdoutแต่ด้วยsys.stdout.writeแทนที่จะพิมพ์ (เพื่อให้ฉันสามารถรองรับเอาต์พุตไปยังไฟล์อื่นได้เช่นกัน)

จากเอกสารของ BeautifulSoupฉันแก้ไขมันด้วยไลบรารี่ codecs:

import sys
import codecs

def main(fIn, fOut):
    soup = BeautifulSoup(fIn)
    # Do processing, with data including non-ASCII characters
    fOut.write(unicode(soup))

if __name__ == '__main__':
    with (sys.stdin) as fIn: # Don't think we need codecs.getreader here
        with codecs.getwriter('utf-8')(sys.stdout) as fOut:
            main(fIn, fOut)

0

ปัญหานี้มักเกิดขึ้นเมื่อโครงการ django ปรับใช้ Apache เนื่องจาก Apache ตั้งค่าตัวแปรสภาพแวดล้อม LANG = C ใน / etc / sysconfig / httpd เพียงแค่เปิดไฟล์และแสดงความคิดเห็น (หรือเปลี่ยนเป็นผู้ช่วยให้รอดของคุณ) การตั้งค่านี้ หรือใช้ตัวเลือก lang ของคำสั่ง WSGIDaemonProcess ในกรณีนี้คุณจะสามารถตั้งค่าตัวแปรสภาพแวดล้อม LANG ที่แตกต่างกันเป็น virtualhosts ที่แตกต่างกัน


0

โซลูชันที่แนะนำไม่ได้ผลสำหรับฉันและฉันสามารถใช้ชีวิตกับการทิ้งอักขระที่ไม่ใช่ ASCII ทั้งหมดได้

s = s.encode('ascii',errors='ignore')

ซึ่งทิ้งฉันไว้กับบางสิ่งที่ถูกปล้นซึ่งไม่ทำให้เกิดข้อผิดพลาด


0

สิ่งนี้จะได้ผล:

 >>>print(unicodedata.normalize('NFD', re.sub("[\(\[].*?[\)\]]", "", "bats\xc3\xa0")).encode('ascii', 'ignore'))

เอาท์พุท:

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