Tengo una cadena, w, y quiero reemplazar "$_" con "<sub>" y el primer "$" después de "$_" con "</sub>". Necesito hacer lo mismo reemplazando "$^" con "<sup>" y "$" después con "</sup>". Intenté w.replace("$_", "<sub>") y w.replace("$", "</sub>"), pero no puedo obtener solo el primer "$" después de "$_" para ser reemplazado por "</sub>", solo cada {{X15} } después de. Lo mismo sigue para reemplazar "$^" con "<sup>". ¿Cómo puedo llamar solo a los "$" directamente después de los indicadores "$_" o "$^" para cambiar y no al resto?

Código Python:

w = ["Li$_3$O$^cat$", "Al$_2$O$_3$", "ZnO", "H$_2$O+O$^3$"]
w = str(w)
if '$_' in w:
    w = w.replace("$_", "<sub>") 
    w = w.replace("$", "</sub>") 

if '$^' in w: 
    w = w.replace("$^","<sup>")
    w = w.replace("$","</sup>") 

print w

Salida deseada:

['Li< sub >3< /sub >O< sup >cat< /sup >', 
 'Al< sub >2< /sub >O< sub >3< /sub >', 
 'ZnO', 
 'H< sub >2< /sub >O+O< sup >3< /sup >']
3
Zach Thomas 13 ene. 2017 a las 19:06

3 respuestas

La mejor respuesta

Si desea reemplazar todas las instancias (no superpuestas), puede hacer algo como esto:

import re
re.sub(r'\$_([^$]*)\$', r'<sub>\1</sub>', w)

Esto encontrará cada instancia de $_(everything other than $)$ con <sub>(everything other than $)</sub>.

Esto significa que si tiene algo como Li$_3$O$^cat$, se convertirá a Li<sub>3</sub>O$^cat$.

Si también desea convertir $^...$ a <sup>...</sup>, puede aplicar una estrategia similar. A continuación se muestra un ejemplo completo que llena la variable result:

import re

w = ["Li$_3$O$^cat$", "Al$_2$O$_3$", "ZnO", "H$_2$O+O$^3$"]
w = str(w)

result = re.sub(r'\$_([^$]*)\$', r'<sub>\1</sub>', w)
result = re.sub(r'\$\^([^$]*)\$', r'<sup>\1</sup>', result)

print result

Con el resultado final siendo:

['Li<sub>3</sub>O<sup>cat</sup>', 'Al<sub>2</sub>O<sub>3</sub>', 'ZnO', 'H<sub>2</sub>O+O<sup>3</sup>']

Dicho esto, si el conjunto completo de sustituciones que hay que hacer es más complejo que esto, es posible que desee almacenar las reglas de sustitución en algún tipo de estructura de datos. Por ejemplo:

import re

def substitute(rules, input):
  """Return a string with substitution performed on given input

  rules -- dict specifying the substitution rules
  input -- input string to be substituted
  """

  result = input
  for k, v in rules.iteritems():
    re_str = r'\$' + re.escape(k) + r'([^$]*)\$'
    sub_str = r'<%s>\1</%s>' % (v, v)
    result = re.sub(re_str, sub_str, result)
  return result

rules = {
  '_': 'sub',
  '^': 'sup'
}

w = ["Li$_3$O$^cat$", "Al$_2$O$_3$", "ZnO", "H$_2$O+O$^3$"]
print substitute(rules, str(w))

Salida:

['Li<sub>3</sub>O<sup>cat</sup>', 'Al<sub>2</sub>O<sub>3</sub>', 'ZnO', 'H<sub>2</sub>O+O<sup>3</sup>']

Tenga en cuenta que las soluciones anteriores no tratan con sustituciones anidadas. Estos podrían manejarse utilizando características de expresión regular más avanzadas, como búsqueda negativa, o analizadores completos si es necesario.

1
tavnab 16 ene. 2017 a las 22:28

Puede intentar lo siguiente, que usa una función para decidir qué reemplazo hacer para cada tipo:

import re

def replace(r):
    if r.group(1):
        return "<sub>{}</sub>".format(r.group(1))
    else:
        return "<sup>{}</sup>".format(r.group(2))

w = ["Li$_3$O$^cat$", "Al$_2$O$_3$", "ZnO", "H$_2$O+O$_3$"]

for text in w:
    print re.sub(r"\$_(.*?)\$|\$\^(.*?)\$", replace, text)

Dandote:

Li<sub>3</sub>O<sup>cat</sup>
Al<sub>2</sub>O<sub>3</sub>
ZnO
H<sub>2</sub>O+O<sub>3</sub>

O como una lista de comprensión:

output = [re.sub(r"\$_(.*?)\$|\$\^(.*?)\$", replace, t) for t in w]
1
Martin Evans 13 ene. 2017 a las 16:57

Con regex, puede reemplazar solo la primera aparición usando el parámetro count=1, con esas 2 declaraciones:

w = re.sub(r"\$_","<sub>",w,count=1)
w = re.sub(r"\$","</sub>",w,count=1)

(tenga en cuenta el escape del signo $)

Otra forma es usar str.partition que se divide de acuerdo con la parte izquierda, el separador, la parte derecha y reconstruir una cadena usando un nuevo separador:

parts = w.partition("$_")
w = parts[0]+"<sub>"+parts[2]
parts = w.partition("$")
w = parts[0]+"</sub>"+parts[2]

O

w = "<sub>".join(w.partition("$_")[::2])
w = "</sub>".join(w.partition("$")[::2])
2
Jean-François Fabre 13 ene. 2017 a las 16:20