Domanda

Ho bisogno di analizzare un file di configurazione che assomiglia a questo (semplificato):

<config>
<links>
<link name="Link1" id="1">
 <encapsulation>
  <mode>ipsec</mode>
 </encapsulation>
</link>
<link name="Link2" id="2">
 <encapsulation>
  <mode>udp</mode>
 </encapsulation>
</link>
</links>

Il mio obiettivo è quello di essere in grado di cambiare i parametri specifici per un particolare link, ma sto avendo difficoltà a raggiungere la sostituzione per funzionare correttamente. Ho un espressione regolare che può isolare un valore di parametro su un link specifico, dove il valore è contenuto nel gruppo di cattura 1:

link_id = r'id="1"'
parameter = 'mode'
link_regex = '<link [\w\W]+ %s>[\w\W]*[\w\W]*<%s>([\w\W]*)</%s>[\w\W]*</link>' \
% (link_id, parameter, parameter)

Così,

print re.search(final_regex, f_read).group(1)

stampe     IPSec

Gli esempi nella regex howto tutti sembrano dare per scontato che uno vuole usare il gruppo di cattura nella sostituzione, ma quello che ho bisogno di fare è sostituire il gruppo di cattura in sé (per esempio, cambiare la modalità di Link1 da IPSec a UDP).

È stato utile?

Soluzione

Non sono sicuro che l'avrei fatto in quel modo, ma il modo più veloce sarebbe di spostare le catture:

([\ w \ W] [\ w \ W] <% s>) [\ w \ W] ([\ w \ W] )' e sostituirlo con group1 + modo + group2

Altri suggerimenti

Devo darvi l'immancabile: "non utilizzare le espressioni regolari per fare questo"

Scopri come molto facilmente impressionante è quello di fare questo con BeautifulSoup , per esempio:

>>> from BeautifulSoup import BeautifulStoneSoup
>>> html = """
... <config>
... <links>
... <link name="Link1" id="1">
...  <encapsulation>
...   <mode>ipsec</mode>
...  </encapsulation>
... </link>
... <link name="Link2" id="2">
...  <encapsulation>
...   <mode>udp</mode>
...  </encapsulation>
... </link>
... </links>
... </config>
... """
>>> soup = BeautifulStoneSoup(html)
>>> soup.find('link', id=1)
<link name="Link1" id="1">
<encapsulation>
<mode>ipsec</mode>
</encapsulation>
</link>
>>> soup.find('link', id=1).mode.contents[0].replaceWith('whatever')
>>> soup.find('link', id=1)
<link name="Link1" id="1">
<encapsulation>
<mode>whatever</mode>
</encapsulation>
</link>

Guardando l'espressione regolare non posso davvero dire se questo è esattamente ciò che si voleva fare, ma qualunque cosa sia che si vuole fare, usando una libreria come BeautifulSoup è molto, molto, meglio che cercare di rattoppare un regolare espressione insieme. Consiglio vivamente di andare questo percorso, se possibile.

Questo appare come XML valido, in questo caso non è necessario BeautifulSoup, sicuramente non la regex, basta caricare XML utilizzando ogni buona libreria XML, modificarlo e stamparlo, ecco un approccio utilizzando ElementTree:

import xml.etree.cElementTree as ET

s = """<config>
<links>
<link name="Link1" id="1">
 <encapsulation>
  <mode>ipsec</mode>
 </encapsulation>
</link>
<link name="Link2" id="2">
 <encapsulation>
  <mode>udp</mode>
 </encapsulation>
</link>
</links>
</config>
"""
configElement = ET.fromstring(s)

for modeElement in configElement.findall("*/*/*/mode"):
    modeElement.text = "udp"

print ET.tostring(configElement)

Cambierà tutti gli elementi della modalità a udp, questo è il risultato:

<config>
<links>
<link id="1" name="Link1">
 <encapsulation>
  <mode>udp</mode>
 </encapsulation>
</link>
<link id="2" name="Link2">
 <encapsulation>
  <mode>udp</mode>
 </encapsulation>
</link>
</links>
</config>

Supponendo che il vostro link_regex è corretto, è possibile aggiungere tra parentesi in questo modo:

(<link [\w\W]+ %s>[\w\W]*[\w\W]*<%s>)([\w\W]*)(</%s>[\w\W]*</link>)

e quindi si potrebbe fare:

p = re.compile(link_regex)
replacement = 'foo'
print p.sub(r'\g<1>' + replacement + r'\g<3>' , f_read)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top