如何使用Python cx_Oracle从US7ASCII Oracle读取国家字符(>127)?

2024-10-02 06:36:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我对显示“英联”的民族字符有问题王国.US7ASCII“使用Python 3.3 cx_Oracle 5.1.2和”NLS_LANG“环境变量的Oracle 11数据库。 Db表列类型为“VARCHAR2(2000字节)”

如何在Python中显示来自Oracle US7ASCII的字符串“£aÀÃÄÆÈ”?这将是某种黑客攻击。 hank可以在所有其他脚本语言Perl、PHP、PL/SQL和python2.7中工作,但在python3.3中却不能工作。在

在oracle11数据库中,我创建了安全性_提示。回答=“一个··············。应答列类型为“VARCHAR2(2000字节)”。在

现在,当使用cxu Oracle和默认NLS LANG时,我得到“a”

当使用NLS_LANG=“ENGLISH_UNITED”时王国.US7ASCII“我明白了

"UnicodeDecodeError: 'ascii' codec can't decode byte 0xa3 in position 0: ordinal not in range(128)"

更新1 我取得了一些进展。当切换到Python2.7和用于Python2.7的cx峎oracle5.1.2时,问题就消失了(我从数据库中获得了全部>;127个字符)。在Python中,2个字符串表示为字节,而在python3中+字符串表示为unicode。我仍然需要Python3.3的最佳解决方案。在

更新2 这个问题的一个可能的解决方案是使用rawtohex(utl_生的。铸成的参见下面的代码。在

^{pr2}$

我的脚本的源代码在GitHubGitHub Sollution下面或下面

def test_nls(nls_lang=None):
    print (">>> run test_nls for %s" %(nls_lang))
    if nls_lang:
        os.environ["NLS_LANG"] = nls_lang
    os.environ["ORA_NCHAR_LITERAL_REPLACE"] = "TRUE"

    connection = get_connection()
    cursor = connection.cursor()
    print("version=%s\nencoding=%s\tnencoding=%s\tmaxBytesPerCharacter=%s" %(connection.version, connection.encoding,
            connection.nencoding, connection.maxBytesPerCharacter))

    cursor.execute("SELECT USERENV ('language') FROM DUAL")
    for result in cursor:
        print("%s" %(result))

    cursor.execute("select ANSWER from SECURITY_HINTS where USERID = '...'")
    for rawValue in cursor:
        print("query returned [%s]" % (rawValue))
        answer = rawValue[0]
    str = ""
    for iterating_var in answer:
        str = ("%s [%d]" % (str, ord(iterating_var)))

    print ("str %s" %(str))

    cursor.close()
    connection.close()

if __name__ == '__main__':
    test_nls()
    test_nls(".AL32UTF8")
    test_nls("ENGLISH_UNITED KINGDOM.US7ASCII")

请参阅下面的日志输出。在

run test_nls for None
version=11.1.0.7.0
encoding=WINDOWS-1252   nencoding=WINDOWS-1252  maxBytesPerCharacter=1
ENGLISH_UNITED KINGDOM.US7ASCII
query returned [¿a¿¿¿¿¿¿¿¿¿]
str  [191] [97] [191] [191] [191] [191] [191] [191] [191] [191] [191


run test_nls for .AL32UTF8
version=11.1.0.7.0
encoding=UTF-8  nencoding=UTF-8 maxBytesPerCharacter=4
AMERICAN_AMERICA.US7ASCII
query returned [�a���������]
str  [65533] [97] [65533] [65533] [65533] [65533] [65533] [65533] [65533] [65533] [65533]

run test_nls for ENGLISH_UNITED KINGDOM.US7ASCII
version=11.1.0.7.0
encoding=US-ASCII   nencoding=US-ASCII  maxBytesPerCharacter=1
ENGLISH_UNITED KINGDOM.US7ASCII
Traceback (most recent call last):
  File "C:/dev/tmp/Python_US7ASCII_cx_Oracle/showUS7ASCII.py", line 71, in <module>
    test_nls("ENGLISH_UNITED KINGDOM.US7ASCII")
  File "C:/dev/tmp/Python_US7ASCII_cx_Oracle/showUS7ASCII.py", line 55, in test_nls
    for rawValue in cursor:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa3 in position 0: ordinal not in range(128)

我试图在Django网页上显示它。但是每个字符都是以代码191或65533作为字符的。在

我看着 choosing NLS_LANG for OracleImporting from Oracle using the correct encoding with Python

Cannot Insert Unicode Using cx-Oracle


Tags: intestlangforenglishconnectioncursorunited
2条回答

我认为你不应该再耍这种恶作剧了。NLS_LANG只需设置为客户端的默认编码。看看更可靠的选择:

  1. 扩展数据库的字符集以允许在VARCHAR列中使用这些字符。在
  2. 将此列升级为NVARCHAR。您也许可以为这个列使用一个新名称,并使用旧名称创建一个VARCHAR计算列,供遗留应用程序读取。在
  3. 保持数据库原样,但在输入数据时检查数据,并用可接受的等效ASCII字符替换所有非ASCII字符。在

哪个选项最好取决于非ASCII字符的常见程度。如果有更多相同问题的表,我建议选择1。如果这是唯一的表,选项2。如果整个表中只有几个非ASCII字符,并且它们的丢失不是什么大问题:选项3。在

如果一个新的或未定义的数据被强行插入数据库,那么当你不能正确地将一个新的或未定义的数据插入数据库中时,你会发现新的或未定义的数据插入数据库。在


编辑:请参阅Oracle对NLS_LANG faq中类似设置示例的评论(我的重点是):

A database is created on a UNIX system with the US7ASCII character set. A Windows client connecting to the database works with the WE8MSWIN1252 character set (regional settings -> Western Europe /ACP 1252) and the DBA, use the UNIX shell (ROMAN8) to work on the database. The NLS_LANG is set to american_america.US7ASCII on the clients and the server.

Note:

This is an INCORRECT setup to explain character set conversion, don't use it in your environment!

如果您想在客户机应用程序中获得未更改的ASCII字符串,最好的方法是以二进制模式从DB传输它。所以,第一次转换必须在服务器端借助^{}包和标准^{}函数关闭。在

您在cursor.execute中选择的内容可能如下所示:

select rawtohex(utl_raw.cast_to_raw(ANSWER)) from SECURITY_HINTS where USERID = '...'

在客户机上,您得到了一个十六进制字符的字符串,它可以在^{}函数的帮助下转换为字符串表示:

^{pr2}$

另外,我不懂Python语言,所以最后的语句可能不正确。在

相关问题 更多 >

    热门问题