Как я могу заменить ‘

#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
  

Может помочь для согласованности?