Как написать ElementTree с удаленным UTF-8

#python #unicode #utf-8 #tostring #elementtree

#python #юникод #utf-8 #tostring #elementtree

Вопрос:

У меня есть гигантское (50 МБ) XML ElementTree, которое я сгенерировал, и где-то в необработанных данных были некоторые буквы UTF-8, которые не были удалены. Похоже, что ElementTree.write и .tostring не работают с юникодом, хотя в tostring есть опция «encoding= ‘UTF-8′». Документы довольно ограничены, и я даже не уверен, что tostring поддерживает UTF-8 (глядя на источник).

Итак, мой вопрос — как мне очистить все это elementtree от любых символов, отличных от ascii, чтобы я мог записать этого монстра на диск (на создание которого ушло 8 часов)? На данный момент я его замариновал. Я также использовал функцию с именем latin1_to_ascii для большинства данных:

 def latin1_to_ascii(unicrap):
        """
        This takes a UNICODE string and replaces Latin-1 characters with
        something equivalent in 7-bit ASCII. Anything not converted is deleted.
    #the unicode hammer approach: http://code.activestate.com/recipes/251871-latin1-to-ascii-the-unicode-hammer/
    """
    xlate={0xc0:'A', 0xc1:'A', 0xc2:'A', 0xc3:'A', 0xc4:'A', 0xc5:'A',
            0xc6:'Ae', 0xc7:'C',
            0xc8:'E', 0xc9:'E', 0xca:'E', 0xcb:'E',
            0xcc:'I', 0xcd:'I', 0xce:'I', 0xcf:'I',
            0xd0:'Th', 0xd1:'N',
            0xd2:'O', 0xd3:'O', 0xd4:'O', 0xd5:'O', 0xd6:'O', 0xd8:'O',
            0xd9:'U', 0xda:'U', 0xdb:'U', 0xdc:'U',
            0xdd:'Y', 0xde:'th', 0xdf:'ss',
            0xe0:'a', 0xe1:'a', 0xe2:'a', 0xe3:'a', 0xe4:'a', 0xe5:'a',
            0xe6:'ae', 0xe7:'c',
            0xe8:'e', 0xe9:'e', 0xea:'e', 0xeb:'e',
            0xec:'i', 0xed:'i', 0xee:'i', 0xef:'i',
            0xf0:'th', 0xf1:'n',
            0xf2:'o', 0xf3:'o', 0xf4:'o', 0xf5:'o', 0xf6:'o', 0xf8:'o',
            0xf9:'u', 0xfa:'u', 0xfb:'u', 0xfc:'u',
            0xfd:'y', 0xfe:'th', 0xff:'y',
            0xa1:'!', 0xa2:'{cent}', 0xa3:'{pound}', 0xa4:'{currency}',
            0xa5:'{yen}', 0xa6:'|', 0xa7:'{section}', 0xa8:'{umlaut}',
            0xa9:'{C}', 0xaa:'{^a}', 0xab:'<<', 0xac:'{not}',
            0xad:'-', 0xae:'{R}', 0xaf:'_', 0xb0:'{degrees}',
            0xb1:'{ /-}', 0xb2:'{^2}', 0xb3:'{^3}', 0xb4:"'",
            0xb5:'{micro}', 0xb6:'{paragraph}', 0xb7:'*', 0xb8:'{cedilla}',
            0xb9:'{^1}', 0xba:'{^o}', 0xbb:'>>', 
            0xbc:'{1/4}', 0xbd:'{1/2}', 0xbe:'{3/4}', 0xbf:'?',
            0xd7:'*', 0xf7:'/',0x92:'a'
            }
    r = ''
    for i in unicrap:
            if xlate.has_key(ord(i)):
                    r  = xlate[ord(i)]
            elif ord(i) >= 0x80:
                    pass
            else:
                    r  = str(i)
    return r
 

эта функция «ядерной опции» работает только со строками, и теперь, когда у меня есть данные в элементе, я, похоже, не могу удалить материал, который я пропустил.

Комментарии:

1. 8 часов? Используете ли вы xml.etree.ElementTree или xml.etree.cElementTree ? Может быть очень продуктивным нажатием клавиши…

Ответ №1:

Вам нужно объяснить «где-то в необработанных данных были некоторые буквы UTF-8, которые не были удалены» — например, что такое «буква UTF-8» и почему вы хотите их удалить.

Также было бы полезно, если бы вы объяснили, что означает «ElementTree.write и .tostring, похоже, задыхаются в юникоде». Пожалуйста, отредактируйте свой вопрос, чтобы показать полное сообщение об ошибке и обратную трассировку.

Почему вы хотите использовать эту функцию для преобразования вашего unicode в ASCII? Это просто для преодоления проблем, с которыми вы сталкиваетесь?

Вероятно, вы передаете str объекты, закодированные в UTF-8, в ElementTree. Не делайте этого. Передайте ему unicode объекты, и он просто работает:

 >>> e = et.Element('root')
>>> e.text = u''.join(unichr(i) for i in xrange(0x400, 0x408))
>>> e.text
u'u0400u0401u0402u0403u0404u0405u0406u0407'
 

Если у вас должен быть вывод ASCII (вы обмениваетесь данными по каналу шириной 7 бит?):

 >>> et.tostring(e)
'<root>amp;#1024;amp;#1025;amp;#1026;amp;#1027;amp;#1028;amp;#1029;amp;#1030;amp;#1031;</root>'
 

UTF-8 работает:

 >>> et.tostring(e, 'UTF-8')
"<?xml version='1.0' encoding='UTF-8'?>n<root>xd0x80xd0x81xd0x82xd0x83xd0x84xd0x85xd0x86xd0x87</root>"
 

Вы должны использовать метод ElementTree.write для записи вашего файла, предпочитая использовать ‘tostring’; это экономит двойную обработку.

Комментарии:

1. Результатом этого скрипта python является XML-файл, интерпретируемый другой проприетарной программой, которая принимает только ascii-Us или latin1, а не unicode. Итак, есть ли какой-либо удобный способ изменить каждый элемент и подэлемент, тег, хвост и т. Д. В ElementTree, как если бы это была строка? Это позволило бы мне просто читать каждую букву и возвращать символ с ord[128] или меньше. Но пока не видел ничего подобного.

Ответ №2:

Я бы снова запустил процесс, декодируя входные строки в юникод во время создания дерева. Восемь часов могут быть долгим временем, но вы можете делать другие вещи вместо того, чтобы ждать указателей на исправление в памяти от других.

Обязательно протестируйте небольшое подмножество данных, чтобы убедиться, что ваш код работает, прежде чем продолжить.

Ответ №3:

мне кажется, что проблема, скорее всего, заключается в кодировке выходного файла, с которым вы работаете. не могли бы вы предоставить больше кода для того, как вы пытаетесь его записать? Я не вижу, как ElementTree.write() и ElementTree.tostring() , возможно, задыхаюсь от этого.

Ответ №4:

Хорошо, даже если вы, ребята, думаете, что я сумасшедший, делая это таким образом, это работает:

Я открыл файл pickle в Notepad и вручную нашел все символы » x??» с регулярным выражением и удалил их. Затем я импортировал pickle в python для сохранения в виде XML-файла, используя ElementTree в командной строке:

f = open(‘pulsewire/pulse_cleaned.pickle’,’rb’)

импорт pickle

данные = рассол.загрузить (f)

импортируйте xml.etree.ElementTree как ET

bob = ET.ElementTree(data) <— необходимо сначала обернуть элемент в дерево

bob.write(«pulsewire/testtree.xml «)