python - xmlcharrefreplace - UnicodeEncodeError:'ascii'編碼解碼器不能在位置20編碼字符u'\ xa0':序號不在範圍內(128)




python3 decode (12)

我在處理來自不同網頁(位於不同網站)的文本中的Unicode字符時遇到問題。 我正在使用BeautifulSoup。

問題在於錯誤不總是可重現的; 它有時可以與一些頁面一起工作,有時它通過拋出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)

我懷疑這是因為某些網頁(或更具體地說,來自某些網站的網頁)可能被編碼,而其他網頁可能未編碼。 所有網站都設在英國並提供用於英國消費的數據 - 因此不存在與內部化或處理用英文以外的其他文字相關的問題。

有沒有人有任何想法如何解決這個問題,以便我可以一致解決這個問題?


下面的解決方案為我工作,剛剛添加

你“串”

(表示字符串為unicode)在我的字符串之前。

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

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

以及我嘗試了一切,但它沒有幫助,谷歌搜索後,我覺得以下,它有幫助。 python 2.7正在使用中。

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

問題是你試圖打印一個Unicode字符,但你的終端不支持它。

你可以嘗試安裝language-pack-en軟件包來解決這個問題:

sudo apt-get install language-pack-en

它為所有支持的軟件包(包括Python)提供英文翻譯數據更新。 根據需要安裝不同的語言包(具體取決於您要打印的字符)。

在某些Linux發行版中,為了確保默認英文語言環境正確設置(因此unicode字符可以由shell /終端處理),需要它。 有時安裝它比手動配置更容易。

然後在編寫代碼時,確保在代碼中使用正確的編碼。

例如:

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

如果仍有問題,請仔細檢查您的系統配置,例如:

  • 你的locale文件( /etc/default/locale ),它應該有例如

    LANG="en_US.UTF-8"
    LC_ALL="en_US.UTF-8"
    
  • LANG / LC_CTYPE在shell中的值。

  • 通過以下方式檢查您的shell支持哪些區域

    locale -a | grep "UTF-8"
    

在新鮮虛擬機中演示問題和解決方案。

  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");'
    ™
    

在Django中使用本地化的fixtures運行manage.py migrate時,我們發現了這個錯誤。

我們的源文件包含# -*- coding: utf-8 -*-聲明,MySQL已正確配置為utf8,並且Ubuntu在/etc/default/locale具有相應的語言包和值。

問題在於Django容器(我們使用docker)缺少LANG env var。

LANG設置為en_US.UTF-8並在重新運行遷移之前重新啟動容器可解決問題。


如果你有類似於packet_data = "This is data"那麼在初始化packet_data之後packet_data在下一行執行此packet_data

unic = u''
packet_data = unic

實際上,我發現在我的大多數情況下,僅僅刪除這些字符就簡單多了:

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

導致即使打印失敗的一個微妙問題是你的環境變量設置錯誤,例如。 這裡LC_ALL設置為“C”。 在Debian中,他們不鼓勵設置它: Debian Wiki on 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à

您需要閱讀Python Unicode HOWTO 。 這個錯誤是第一個例子

基本上,停止使用str從unicode轉換為編碼文本/字節。

相反,正確使用.encode()來編碼字符串:

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

或完全以unicode工作。


我只是使用了以下內容:

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

檢查一下文檔中提到的有關內容

unicodedata.normalize(form,unistr)返回Unicode字符串unistr的標準表單形式。 表單的有效值為'NFC','NFKC','NFD'和'NFKD'。

Unicode標準根據規範等價和兼容性等價的定義來定義Unicode字符串的各種規範化形式。 在Unicode中,可以用各種方式表示幾個字符。 例如,字符U + 00C7(帶有CEDILLA的拉丁大寫字母C)也可以表示為序列U + 0043(拉丁文大寫字母C)U + 0327(CEDILLA組合)。

對於每個字符,有兩種正常形式:標準形式C和標準形式D.標準形式D(NFD)也稱為規範分解,並將每個字符轉換為其分解形式。 標準形式C(NFC)首先應用規範分解,然後再組合預先組合的字符。

除了這兩種形式之外,還有兩種基於兼容性等效的額外正常形式。 在Unicode中,支持通常與其他字符統一的某些字符。 例如,U + 2160(ROMAN NUMERAL ONE)與U + 0049(拉丁大寫字母I)確實是相同的東西。 但是,Unicode支持與現有字符集兼容(例如gb2312)。

標準格式KD(NFKD)將應用兼容性分解,即將所有兼容性字符替換為它們的等價物。 標準形式KC(NFKC)首先應用兼容性分解,然後是規範組合。

即使兩個unicode字符串被標準化,並且與人類閱讀器看起來相同,如果一個字符組合了字符而另一個字符串沒有,它們可能不會相等。

為我解決它。 簡單而簡單。


我發現優雅的解決方案可以刪除符號,並繼續將字符串保留為字符串,如下所示:

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

需要注意的是,使用ignore選項很危險,因為它默默地從使用它的代碼中刪除任何unicode(和國際化)支持,如下所示:

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

簡單的幫手功能在here找到。

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')

這是一個經典的Python 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使用默認的字符編碼來嘗試編碼你給它的字節,在你的情況下有時候是unicode字符的表示。 為了解決這個問題,你必須告訴python如何使用.encode('whatever_unicode')來處理你給它的字符串。 大多數時候,你應該很好地使用utf-8。

有關此主題的詳細介紹,請參閱此處的Ned Batchelder的PyCon講座: http://nedbatchelder.com/text/unipain.html : http://nedbatchelder.com/text/unipain.html





python-unicode