regex Python:使用sub()替换正则表达式匹配的字符串

s4chpxco  于 2023-03-20  发布在  Python
关注(0)|答案(3)|浏览(121)

如果一个xml文档中有太多的空格(我不能修改文件生成器,所以我必须使用这个文件),这会导致解释错误,我需要删除每个“〉”符号后面和每个“〈”符号前面的空格。我尝试使用python脚本和函数**sub(pattern,repl,string)**来完成此操作
模式i使用两个不同的正则表达式,如下例所示

line = re.sub(r"\s*<", "<", line)   #to remove every spaces after '>' symbol
line = re.sub(r">\s*", ">", line)  #to before every '<' symbol

第一个按预期工作,但第二个不匹配任何东西,尽管正则表达式是正确的(用正则表达式检查器检查)。
你有什么建议吗?
下面是一个完整的示例:

import re
import os
f2 = open(r"C:\output_clean.xml", "a")

lines = open(r"C:\output.xml", "r").readlines()
for line in lines:
        line = re.sub(r"\s*<", "<", line)
        line = re.sub(r">\s*", ">", line)
        
        f2.write(line)

f2.close()

实际的文件output.xml非常长,所以我只报告了其中的一部分(对于示例的目的来说,这并不重要):

<?xml version="1.0"?><ImportExportG1>   <DOCVENTE>      <TIPDOC>         B1      </TIPDOC>      <RAGBOL>         A      </RAGBOL>      <ANNDOC>         2023      </ANNDOC>      <NUMDOC>         1072      </NUMDOC>      <DATDOC>         15/03/2023      </DATDOC>      <CLFR>         C      </CLFR>      <CODCLI>         002302      </CODCLI>      <CAMBIO>         0      </CAMBIO>      <RIFCAMBIO>         E      </RIFCAMBIO>      <SCOFIN1>         0      </SCOFIN1>      <SCOFIN2>         0      </SCOFIN2>      <SCONTO>         0      </SCONTO>      <PDCSCO>         210201      </PDCSCO>      <CODMAG>         01      </CODMAG>      <CAUMAG>         202      </CAUMAG>      <CODPAG>         B001      </CODPAG>      <CODVET>         025      </CODVET>      <CODPOR>         001      </CODPOR>      <CODTRA>         001      </CODTRA>      <ASPETTO>         Pallet      </ASPETTO>      <PESO>         150      </PESO>      <COLLI>         1      </COLLI>

预期结果(在output_clean.xml内):

<?xml version="1.0"?><ImportExportG1><DOCVENTE><TIPDOC>B1</TIPDOC><RAGBOL>A</RAGBOL><ANNDOC>2023</ANNDOC><NUMDOC>1072</NUMDOC><DATDOC>15/03/2023</DATDOC><CLFR>C</CLFR><CODCLI>002302</CODCLI><CAMBIO>0</CAMBIO><RIFCAMBIO>E</RIFCAMBIO><SCOFIN1>0</SCOFIN1><SCOFIN2>0</SCOFIN2><SCONTO>0</SCONTO><PDCSCO>210201</PDCSCO><CODMAG>01</CODMAG><CAUMAG>202</CAUMAG><CODPAG>B001</CODPAG><CODVET>025</CODVET><CODPOR>001</CODPOR><CODTRA>001</CODTRA><ASPETTO>Pallet</ASPETTO><PESO>150</PESO><COLLI>1</COLLI>

实际结果(在output_clean.xml内):

<?xml version="1.0"?><ImportExportG1><DOCVENTE><TIPDOC>         B1</TIPDOC><RAGBOL>         A</RAGBOL><ANNDOC>         2023</ANNDOC><NUMDOC>         1072</NUMDOC><DATDOC>         15/03/2023</DATDOC><CLFR>         C</CLFR><CODCLI>         002302</CODCLI><CAMBIO>         0</CAMBIO><RIFCAMBIO>         E</RIFCAMBIO><SCOFIN1>         0</SCOFIN1><SCOFIN2>         0</SCOFIN2><SCONTO>         0</SCONTO><PDCSCO>         210201</PDCSCO><CODMAG>         01</CODMAG><CAUMAG>         202</CAUMAG><CODPAG>         B001</CODPAG><CODVET>         025</CODVET><CODPOR>         001</CODPOR><CODTRA>         001</CODTRA><ASPETTO>         Pallet</ASPETTO><PESO>         150</PESO><COLLI>         1</COLLI>

先谢谢你

8wigbo56

8wigbo561#

免责声明:使用正则表达式来清理XML内容通常是邪恶的,是一种威胁,应该将这项任务委托给适当的解析器。如果您没有嵌套标记,可以尝试使用以下替换逻辑:

inp = '<?xml version="1.0"?><ImportExportG1>   <DOCVENTE>      <TIPDOC>         B1      </TIPDOC>      <RAGBOL>         A      </RAGBOL>      <ANNDOC>         2023      </ANNDOC>      <NUMDOC>         1072      </NUMDOC>      <DATDOC>         15/03/2023      </DATDOC>      <CLFR>         C      </CLFR>      <CODCLI>         002302      </CODCLI>      <CAMBIO>         0      </CAMBIO>      <RIFCAMBIO>         E      </RIFCAMBIO>      <SCOFIN1>         0      </SCOFIN1>      <SCOFIN2>         0      </SCOFIN2>      <SCONTO>         0      </SCONTO>      <PDCSCO>         210201      </PDCSCO>      <CODMAG>         01      </CODMAG>      <CAUMAG>         202      </CAUMAG>      <CODPAG>         B001      </CODPAG>      <CODVET>         025      </CODVET>      <CODPOR>         001      </CODPOR>      <CODTRA>         001      </CODTRA>      <ASPETTO>         Pallet      </ASPETTO>      <PESO>         150      </PESO>      <COLLI>         1      </COLLI>'
output = re.sub(r'<.*?>|.*?(?=<.*?>|$)', lambda m: m.group().replace(' ', '') if not m.group().startswith('<') and not m.group().endswith('>') else m.group(), inp)
print(output)

这将打印:

<?xml version="1.0"?><ImportExportG1><DOCVENTE><TIPDOC>B1</TIPDOC><RAGBOL>A</RAGBOL><ANNDOC>2023</ANNDOC><NUMDOC>1072</NUMDOC><DATDOC>15/03/2023</DATDOC><CLFR>C</CLFR><CODCLI>002302</CODCLI><CAMBIO>0</CAMBIO><RIFCAMBIO>E</RIFCAMBIO><SCOFIN1>0</SCOFIN1><SCOFIN2>0</SCOFIN2><SCONTO>0</SCONTO><PDCSCO>210201</PDCSCO><CODMAG>01</CODMAG><CAUMAG>202</CAUMAG><CODPAG>B001</CODPAG><CODVET>025</CODVET><CODPOR>001</CODPOR><CODTRA>001</CODTRA><ASPETTO>Pallet</ASPETTO><PESO>150</PESO><COLLI>1</COLLI>

此处使用的正则表达式模式匹配:

  • <.*?> XML标记
  • |
  • .*?(?=<.*?>|$)任何中间内容,直到(但不包括)下一个XML标记或字符串末尾

我们执行lambda替换,它选择性地只从中间内容中剥离空格,而不从标记本身中剥离空格。

dvtswwa3

dvtswwa32#

您可以使用lookarounds并替换为空字符串,将两个条件放在一个模式中:

import re
input_str = """<?xml version="1.0"?><ImportExportG1>   <DOCVENTE>      <TIPDOC>         B1      </TIPDOC>      <RAGBOL>         A      </RAGBOL>      <ANNDOC>         2023      </ANNDOC>      <NUMDOC>         1072      </NUMDOC>      <DATDOC>         15/03/2023      </DATDOC>      <CLFR>         C      </CLFR>      <CODCLI>         002302      </CODCLI>      <CAMBIO>         0      </CAMBIO>      <RIFCAMBIO>         E      </RIFCAMBIO>      <SCOFIN1>         0      </SCOFIN1>      <SCOFIN2>         0      </SCOFIN2>      <SCONTO>         0      </SCONTO>      <PDCSCO>         210201      </PDCSCO>      <CODMAG>         01      </CODMAG>      <CAUMAG>         202      </CAUMAG>      <CODPAG>         B001      </CODPAG>      <CODVET>         025      </CODVET>      <CODPOR>         001      </CODPOR>      <CODTRA>         001      </CODTRA>      <ASPETTO>         Pallet      </ASPETTO>      <PESO>         150      </PESO>      <COLLI>         1      </COLLI>"""
repl_pattern = re.compile(r"\s*(?=<)|(?<=>)\s*")
print(re.sub(repl_pattern, '', input_str))

输出:

<?xml version="1.0"?><ImportExportG1><DOCVENTE><TIPDOC>B1</TIPDOC><RAGBOL>A</RAGBOL><ANNDOC>2023</ANNDOC><NUMDOC>1072</NUMDOC><DATDOC>15/03/2023</DATDOC><CLFR>C</CLFR><CODCLI>002302</CODCLI><CAMBIO>0</CAMBIO><RIFCAMBIO>E</RIFCAMBIO><SCOFIN1>0</SCOFIN1><SCOFIN2>0</SCOFIN2><SCONTO>0</SCONTO><PDCSCO>210201</PDCSCO><CODMAG>01</CODMAG><CAUMAG>202</CAUMAG><CODPAG>B001</CODPAG><CODVET>025</CODVET><CODPOR>001</CODPOR><CODTRA>001</CODTRA><ASPETTO>Pallet</ASPETTO><PESO>150</PESO><COLLI>1</COLLI>

注意:您应该将sub应用于整个文件字符串(open(r"C:\output.xml", "r").read())。逐行阅读,您将错过前面的>

j5fpnvbx

j5fpnvbx3#

我建议您使用lxml

from lxml import etree as ET

xml = '<?xml version="1.0"?><ImportExportG1>   <DOCVENTE>      <TIPDOC>         B1      </TIPDOC>      <RAGBOL>         A      </RAGBOL>      <ANNDOC>         2023      </ANNDOC>      <NUMDOC>         1072      </NUMDOC>      <DATDOC>         15/03/2023      </DATDOC>      <CLFR>         C      </CLFR>      <CODCLI>         002302      </CODCLI>      <CAMBIO>         0      </CAMBIO>      <RIFCAMBIO>         E      </RIFCAMBIO>      <SCOFIN1>         0      </SCOFIN1>      <SCOFIN2>         0      </SCOFIN2>      <SCONTO>         0      </SCONTO>      <PDCSCO>         210201      </PDCSCO>      <CODMAG>         01      </CODMAG>      <CAUMAG>         202      </CAUMAG>      <CODPAG>         B001      </CODPAG>      <CODVET>         025      </CODVET>      <CODPOR>         001      </CODPOR>      <CODTRA>         001      </CODTRA>      <ASPETTO>         Pallet      </ASPETTO>      <PESO>         150      </PESO>      <COLLI>         1      </COLLI></DOCVENTE></ImportExportG1>'
dom = ET.fromstring(xml, ET.XMLParser(remove_blank_text=True))

for elem in dom.iter():
    if elem.text is not None: 
        elem.text = elem.text.strip()

print(ET.tostring(dom).decode())

使用XMLParser(remove_blank_text=True)可以删除节点之间的空格,使用for循环可以删除节点内部的空格。
ET.fromstring用于处理字符串,如果需要处理文件,可以用途:

dom = ET.parse(xmlFilePath, ET.XMLParser(remove_blank_text=True))

相关问题