#python #xml #parsing #replace
#python #xml #синтаксический анализ #заменить
Вопрос:
У меня возникли проблемы с .replace()
. Моему синтаксическому анализатору XML не нравится ‘amp;’, но он примет ‘amp; amp; ‘. Я хотел бы использовать .replace('amp;','amp;amp;')
, но, похоже, это не работает. Я продолжаю получать ошибку:
lxml.etree.XMLSyntaxError: xmlParseEntityRef: no name, line 51, column 41
До сих пор я пробовал только прямой путь file=file.replace('amp;','amp;amp;')
, но это не работает. Я также пробовал:
xml_file = infile
file=xml_file.readlines()
for line in file:
for char in line:
char.replace('amp;','amp;amp;')
infile=open('a','w')
file='n'.join(file)
infile.write(file)
infile.close()
infile=open('a','r')
xml_file=infile
Каков наилучший способ решить мою проблему?
Ответ №1:
str.replace
создает и возвращает новую строку. Он не может изменять строки на месте — они неизменяемы. Попробуйте заменить:
file=xml_file.readlines()
с помощью
file = [line.replace('amp;','amp;amp;') for line in xml_file]
Это использует понимание списка для построения списка, эквивалентного .readlines()
, но с уже произведенной заменой.
Как указано в комментариях, если бы в строке уже были amp;amp;
s, они были бы превращены amp;amp;amp;
, скорее всего, не в то, что вы хотите. Чтобы избежать этого, вы могли бы использовать отрицательный прогноз в регулярном выражении для замены только амперсандов, за которыми еще не следует amp;
:
import re
file = [re.sub("amp;(?!amp;)", "amp;amp;", line) ...]
Комментарии:
1. Однако это проблема, если
line
уже содержитamp;amp;
…2. @Stefan верно, я добавил опцию для этого случая.
3. Потрясающе! Это все еще проблема для других экранированных вещей, таких как
amp;<
though. Я думаю, это выходит за рамки заданного вопроса, но я хотел упомянуть об этом. 🙂4. Наверняка есть функция для автоматического экранирования всех объектов HTML вместо написания собственных?
Ответ №2:
str.replace()
возвращает новый объект string с внесенными изменениями. Это не изменяет данные на месте. Вы игнорируете возвращаемое значение.
Вместо этого вы хотите применить его к каждой строке:
file = [line.replace('amp;', 'amp;amp;') for line in file]
Вы могли бы использовать fileinput()
модуль для выполнения преобразования и попросить его обработать замену исходного файла (будет создана резервная копия):
import fileinput
import sys
for line in fileinput.input('filename', inplace=True):
sys.stdout.write(line.replace('amp;', 'amp;amp;'))
Ответ №3:
Ох… Вам нужно декодировать HTML-нотацию для специальных символов. В Python есть модуль для решения этой проблемы — HTMLParser
, вот некоторые документы.
Вот пример:
import HTMLParser
out_file = ....
file = xml_file.readlines()
parsed_lines = []
for line in file:
parsed_lines.append(htmlparser.unescape(line))
Ответ №4:
Немного не по теме, но, возможно, было бы неплохо использовать некоторые экранирования?
Я часто использую цитату urllib, которая вводит и выводит экранирование HTML:
result=urllib.quote("filenameamp;fileextension")
'filename&fileextension'
urllib.unquote(result)
filenameamp;fileextension
Может помочь для согласованности?