Python не-символы ascii - PullRequest
       4

Python не-символы ascii

2 голосов
/ 29 сентября 2011

У меня есть файл Python, который создает и заполняет таблицу в MS SQL. Единственным камнем преткновения является то, что код ломается, если есть какие-либо не-ascii символы или одиночные апострофы (а их довольно много). Хотя я могу запустить функцию замены, чтобы избавиться от строк апострофов, я бы предпочел оставить их без изменений. Я также пытался преобразовать данные в 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 включен ниже. Я полагаю, что точка в коде, где происходит этот разрыв, находится после следующей строки: 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

Ответы [ 5 ]

3 голосов
/ 29 сентября 2011

Джеймс, я считаю, что реальная проблема в том, что вы не используете Юникод через доску. Попробуйте сделать следующее:

  • Убедитесь, что ваш входной файл, который вы используете для заполнения БД, находится в формате UTF-8 и что вы читаете его с помощью кодера UTF-8.
  • Убедитесь, что ваша БД фактически хранит данные как Unicode
  • Когда вы извлекаете данные из файла или из БД или хотите манипулировать строками (например, с помощью оператора +), вам необходимо убедиться, что все части соответствуют Юникоду. Вы не можете использовать метод str (). Вам нужно использовать unicode (), как указал Дейв. Если вы определяете строки в своем коде, используйте «моя строка» вместо «моя строка» (иначе это не считается юникодом).

Также предоставьте нам полную трассировку стека и имя исключения.

1 голос
/ 29 сентября 2011

Я собираюсь использовать мои навыки психической отладки и сказать, что вы пытаетесь str() если что-то и получаете ошибку с кодеком ascii.Что вы действительно должны сделать, это использовать кодек utf-8 вместо этого, как это:

insert_value_uni = unicode(row.GetValue(CurrentField['Name']))
InsertValue = insert_value_uni.encode('utf-8')
0 голосов
/ 29 сентября 2011

Когда я преобразовал свой str () в юникод, это решило проблему.Простой ответ, и я ценю помощь каждого в этом.

0 голосов
/ 29 сентября 2011

Как правило, вы хотите преобразовать в Unicode при вводе данных и преобразовать в нужную кодировку при выводе.

Так что вам будет легче найти вашу проблему, если вы сделаете это.Это означает изменение всех строк на юникод, «INSERT INTO» на «INSERT INTO».(Обратите внимание на «u» перед строкой) Затем, когда вы отправляете строку для выполнения, преобразуйте в нужную кодировку «utf8».

cursor.execute(InsertSQL.encode("utf8")) # Where InsertSQL is unicode

Кроме того, вы должны добавить строку кодировки в началоваш исходный кодЭто означает добавление файла cookie кодирования в одну из первых двух строк файла:

     #!/usr/bin/python
     # -*- coding: <encoding name> -*-

Если вы извлекаете данные из файла для построения вашей строки, вы можете использовать codecs.open дляавтоматическое преобразование из определенной кодировки в юникод при загрузке.

0 голосов
/ 29 сентября 2011

Или вы можете принять мнение, что разрешен только ASCII, и использовать удивительно названный Unicode Hammer

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...