Python非ASCII字符

3
我有一个Python文件,用于创建和填充MS SQL中的表。唯一的问题是,如果存在任何非ASCII字符或单引号(而且有相当多的这样情况),代码就会出现错误。尽管我可以运行replace函数来清除字符串中的撇号,但我更喜欢保持它们不变。我也尝试将数据转换为UTF-8,但没有成功。
以下是我收到的错误消息:
"'ascii' codec can't encode character u'\2013' in position..." (for non-ascii characters)

对于单引号

class 'pyodbc.ProgrammingError'>: ('42000', "[42000] [Microsoft][ODBC SQL Server Driver][SQL Server] Incorrect syntax near 'S, 230 X 90M.; Eligibilty....  

当我尝试将字符串编码为UTF-8时,却收到了以下错误消息:
<type 'exceptions.UnicodeDecodeError'>: ascii' codec can't decode byte 0xe2 in position 219: ordinal not in range(128)

以下是Python代码。我认为这个break发生在代码的以下行:InsertValue = str (row.GetValue(CurrentField ['Name']))。

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

import pyodbc
import sys
import arcpy
import arcgisscripting

gp = arcgisscripting.create(9.3)
SQL_KEYWORDS = ['PERCENT', 'SELECT', 'INSERT', 'DROP', 'TABLE']

#SourceFGDB = '###'
#SourceTable = '###'
SourceTable = sys.argv[1]
TempInputName = sys.argv[2]
SourceTable2 = sys.argv[3]
#---------------------------------------------------------------------------------------------------------------------
# Target Database Settings
#---------------------------------------------------------------------------------------------------------------------
TargetDatabaseDriver = "{SQL Server}"
TargetDatabaseServer = "###"
TargetDatabaseName = "###"
TargetDatabaseUser = "###"
TargetDatabasePassword = "###"

# Get schema from FGDB table.
# This should be an ordered list of dictionary elements [{'FGDB_Name', 'FGDB_Alias', 'FGDB_Type', FGDB_Width, FGDB_Precision, FGDB_Scale}, {}]

if not gp.Exists(SourceTable):
    print ('- The source does not exist.')
    sys.exit(102)
#### Should see if it is actually a table type.  Could be a Feature Data Set or something...
print('        - Processing Items From : ' + SourceTable)
FieldList = []
Field_List = gp.ListFields(SourceTable)
print('            - Getting number of rows.')
result = gp.GetCount_management(SourceTable)
Number_of_Features = gp.GetCount_management(SourceTable)
print('                - Number of Rows: ' + str(Number_of_Features))
print('            - Getting fields.')
Field_List1 = gp.ListFields(SourceTable, 'Layer')
Field_List2 = gp.ListFields(SourceTable, 'Comments')
Field_List3 = gp.ListFields(SourceTable, 'Category')
Field_List4 = gp.ListFields(SourceTable, 'State')
Field_List5 = gp.ListFields(SourceTable, 'Label')
Field_List6 = gp.ListFields(SourceTable, 'DateUpdate')
Field_List7 = gp.ListFields(SourceTable, 'OBJECTID')
for Current_Field in Field_List1 + Field_List2 + Field_List3 + Field_List4 + Field_List5 + Field_List6 + Field_List7:
        print('            - Field Found: ' + Current_Field.Name)
        if Current_Field.AliasName in SQL_KEYWORDS:
            Target_Name = Current_Field.Name + '_'
        else:
            Target_Name = Current_Field.Name

        print('                 - Alias    : ' + Current_Field.AliasName)
        print('                 - Type     : ' + Current_Field.Type)
        print('                 - Length   : ' + str(Current_Field.Length))
        print('                 - Scale    : ' + str(Current_Field.Scale))
        print('                 - Precision: ' + str(Current_Field.Precision))
        FieldList.append({'Name': Current_Field.Name, 'AliasName': Current_Field.AliasName, 'Type': Current_Field.Type, 'Length': Current_Field.Length, 'Scale': Current_Field.Scale, 'Precision': Current_Field.Precision, 'Unique': 'UNIQUE', 'Target_Name': Target_Name})
# Create table in SQL Server based on FGDB table schema.
cnxn = pyodbc.connect(r'DRIVER={SQL Server};SERVER=###;DATABASE=###;UID=sql_webenvas;PWD=###')
cursor = cnxn .cursor()
#### DROP the table first?
try:
    DropTableSQL = 'DROP TABLE dbo.' + TempInputName + '_Test;'
    print DropTableSQL
    cursor.execute(DropTableSQL)
    dbconnection.commit()
except:
    print('WARNING: Can not drop table - may not exist: ' + TempInputName + '_Test')
CreateTableSQL = ('CREATE TABLE  ' + TempInputName + '_Test '
' (Layer varchar(500), Comments varchar(5000), State int, Label varchar(500), DateUpdate DATETIME, Category varchar(50), OBJECTID int)')
cursor.execute(CreateTableSQL)
cnxn.commit()
# Cursor through each row in the FGDB table, get values, and insert into the SQL Server Table.
# We got Number_of_Features earlier, just use that.
Number_Processed = 0
print('        - Processing ' + str(Number_of_Features) + ' features.')
rows = gp.SearchCursor(SourceTable)
row = rows.Next()
while row:
    if Number_Processed % 10000 == 0:
        print('            - Processed ' + str(Number_Processed) + ' of ' + str(Number_of_Features))
    InsertSQLFields = 'INSERT INTO ' + TempInputName + '_Test ('
    InsertSQLValues = 'VALUES ('
    for CurrentField in FieldList:
        InsertSQLFields = InsertSQLFields + CurrentField['Target_Name'] + ', '
        InsertValue = str(row.GetValue(CurrentField['Name']))
        if InsertValue in ['None']:
            InsertValue = 'NULL'
        # Use an escape quote for the SQL.
        InsertValue = InsertValue.replace("'","' '")
        if CurrentField['Type'].upper() in ['STRING', 'CHAR', 'TEXT']:
            if InsertValue == 'NULL':
                InsertSQLValues = InsertSQLValues + "NULL, "
            else:
                InsertSQLValues = InsertSQLValues + "'" + InsertValue + "', "
        elif CurrentField['Type'].upper() in ['GEOMETRY']:
            ## We're not handling geometry transfers at this time.
            if InsertValue == 'NULL':
                InsertSQLValues = InsertSQLValues + '0' + ', '
            else:
                InsertSQLValues = InsertSQLValues + '1' + ', '
        else:
            InsertSQLValues = InsertSQLValues + InsertValue + ', '
    InsertSQLFields = InsertSQLFields[:-2] + ')'
    InsertSQLValues = InsertSQLValues[:-2] + ')'
    InsertSQL = InsertSQLFields + ' ' + InsertSQLValues
    ## print InsertSQL
    cursor.execute(InsertSQL)
    cnxn.commit()
    Number_Processed = Number_Processed + 1
    row = rows.Next()
print('            - Processed all ' + str(Number_Processed))
del row
del rows

它是如何发生故障的?在哪里发生故障? - Dave
通常会在这个点上出现问题:InsertValue = str(row.GetValue(CurrentField['Name'])). 它会填充它创建的 SQL 表,直到找到一个非 ASCII 字符或单引号,然后就会在那里出错。 - James D.
你得到了什么异常?你能编辑你的问题并添加它吗? - Dave
我能做到,我会做到。这只需要几分钟。 - James D.
这个问题有进展了吗?我已经给出了答案,但是如果能够看到堆栈跟踪的话会更有帮助。谢谢。 - Michael
5个回答

3

詹姆斯,我认为真正的问题是你没有全面使用Unicode。请尝试以下操作:

  • 确保你用来填充数据库的输入文件是UTF-8格式,并且你正在使用UTF-8编码器读取它。
  • 确保你的数据库实际上将数据存储为Unicode格式。
  • 当你从文件或数据库检索数据或想要操作字符串(例如使用+运算符)时,你需要确保所有部分都是正确的Unicode。你不能使用str()方法。你需要使用unicode(),正如Dave所指出的那样。如果你在代码中定义字符串,请使用u'my string'而不是'my string'(否则它不会被视为Unicode)。

此外,请提供完整的堆栈跟踪和异常名称。


2

我将使用我的超能力调试技巧并猜测你正在尝试使用str()方法对某些内容进行转换,但是出现了ascii编码错误。实际上,你应该改用utf-8编码,像这样:

insert_value_uni = unicode(row.GetValue(CurrentField['Name']))
InsertValue = insert_value_uni.encode('utf-8')

当我尝试这样做时,我得到了另一个错误,即在尝试使用utf-8编码时遇到的错误。'ascii'编解码器无法解码位于219位置的0xe2字节:序数不在范围内(128)。 - James D.
@JamesD,你能把整个回溯信息放在你的问题里吗?记得缩进以保留格式。 - Dave

1

或者你可以认为只允许使用ASCII,并使用一个非常棒的名字叫做Unicode Hammer


0
通常情况下,您希望在数据输入时转换为Unicode,在输出时转换为所需的编码。
如果这样做,您将更容易找到问题。这意味着将所有字符串更改为Unicode,将'INSERT INTO'更改为u'INSERT INTO'。(请注意字符串前面的“u”) 然后,当您发送要执行的字符串时,将其转换为所需的编码,“utf8”。
cursor.execute(InsertSQL.encode("utf8")) # Where InsertSQL is unicode

此外,您应该在源代码顶部添加编码字符串。这意味着将编码 cookie 添加到文件的前两行之一:
     #!/usr/bin/python
     # -*- coding: <encoding name> -*-

如果您正在从文件中提取数据以构建字符串,则可以使用codecs.open在加载时自动将特定编码转换为Unicode。

0
当我将我的str()转换为unicode时,问题得到了解决。这是一个简单的答案,我感谢大家对此的帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接