2008-10-13 5 views
14

Tengo un archivo cuyo formato estoy alterando a través de un script de Python. Tengo varias cadenas en camello en este archivo donde solo quiero insertar un espacio antes de la letra mayúscula, por lo que "WordWordWord" se convierte en "Word Word Word".Estoy buscando una forma pitónica para insertar un espacio antes de mayúsculas

Mi limitada experiencia en expresiones regulares solo se detuvo en mí - ¿alguien puede pensar en una expresión regular decente para hacer esto, o (mejor aún) hay una manera más pitonica de hacer esto que me estoy perdiendo?

Respuesta

23

Usted podría intentar:

>>> re.sub(r"(\w)([A-Z])", r"\1 \2", "WordWordWord") 
'Word Word Word' 
+1

re.sub (r "(\ w) ([AZ])", r "\ 1 \ 2", "SorryIThinkYouMissedASpot") – tzot

+0

Como pequeña mejora, se debería usar [[: upper:]] en lugar de [AZ]. – Tomalak

+4

@Tomalak, '[[: upper:]]' no es compatible con Python. Es una [expresión de paréntesis POSIX] (http://www.regular-expressions.info/posixbrackets.html). –

3

Con expresiones regulares se puede hacer esto:

re.sub('([A-Z])', r' \1', str) 

Por supuesto, esto sólo funcionará para los caracteres ASCII, si usted quiere hacer Unicode es una nueva lata de gusanos :-)

+1

re.sub ('([A-Z])', r '\ 1', "¿Queremos un espacio antes de los D's de esta frase?") – tzot

+0

Ah, sí, buen punto. Parece que las soluciones de tu y Leonhard manejan esto correctamente. –

24

Si hay mayúsculas consecutivas, entonces el resultado de Gregs podría ser no es lo que busca, ya que \ w consume el caracter en frente de la carta capial para ser reemplazado.

>>> re.sub(r"(\w)([A-Z])", r"\1 \2", "WordWordWWWWWWWord") 
'Word Word WW WW WW Word' 

Una mirada detrás resolvería esto:

>>> re.sub(r"(?<=\w)([A-Z])", r" \1", "WordWordWWWWWWWord") 
'Word Word W W W W W W Word' 
+0

La respuesta de Dan es mejor y más simple :) – hayalci

+0

@hayalci: re.sub ('([A-Z])', r '\ 1', '¿De verdad?') – tzot

8

Tener un vistazo a mi respuesta en .NET - How can you split a “caps” delimited string into an array?

Editar: Tal vez mejor incluir aquí.

re.sub(r'([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))', r'\1 ', text) 

Por ejemplo:

"SimpleHTTPServer" => ["Simple", "HTTP", "Server"] 
+0

Tu respuesta es probablemente lo que Electrons_Ahoy realmente quiere; sin embargo, según el fraseo de su pregunta, no lo es. – tzot

+0

pero gracias por compartir este, esta es una respuesta increíble! –

10

Quizás más corto:

>>> re.sub(r"\B([A-Z])", r" \1", "DoIThinkThisIsABetterAnswer?") 
+1

Para cualquiera que se pregunte, '\ B' es" Sin límite de palabra ". Entonces no está insertando espacios donde ya hay un espacio. – ArtOfWarfare

0

Estoy de acuerdo en que la solución de expresiones regulares es el más fácil, pero yo no diría que es el más Pythonic.

¿Qué tal:

text = 'WordWordWord' 
new_text = '' 

for i, letter in enumerate(text): 
    if i and letter.isupper(): 
     new_text += ' ' 

    new_text += letter 
+0

Esto tiene el mismo problema que el de Dan: obtendrá espacios adicionales antes de mayúsculas, incluso si no son necesarios. – Brian

+0

Cierto, lo he editado para agregar una bandera ... Admito que es un poco engorroso, pero puede ser más fácil de recordar que la expresión regular. – monkut

0

Creo expresiones regulares son el camino a seguir aquí, pero sólo para dar una versión de Python puro sin (con suerte) ninguno de los problemas ΤΖΩΤΖΙΟΥ ha señalado:

def splitCaps(s): 
    result = [] 
    for ch, next in window(s+" ", 2): 
     result.append(ch) 
     if next.isupper() and not ch.isspace(): 
      result.append(' ') 
    return ''.join(result) 

ventana() es una función de utilidad que utilizo para operar en una ventana deslizante de artículos, que se define como:

import collections, itertools 

def window(it, winsize, step=1): 
    it=iter(it) # Ensure we have an iterator 
    l=collections.deque(itertools.islice(it, winsize)) 
    while 1: # Continue till StopIteration gets raised. 
     yield tuple(l) 
     for i in range(step): 
      l.append(it.next()) 
      l.popleft() 
2

Tal vez usted estaría interesado en la aplicación de una sola línea sin necesidad de utilizar expresiones regulares:

''.join(' ' + char if char.isupper() else char.strip() for char in text).strip() 
1

Si tiene acrónimos, es probable que no quieren espacios entre ellos.Esta expresión regular de dos etapas mantendrá intacta siglas (y también el tratamiento de puntuacion y otras letras mayúsculas no como algo para agregar un espacio en):

re_outer = re.compile(r'([^A-Z ])([A-Z])') 
re_inner = re.compile(r'(?<!^)([A-Z])([^A-Z])') 
re_outer.sub(r'\1 \2', re_inner.sub(r' \1\2', 'DaveIsAFKRightNow!Cool')) 

la salida será: 'Dave Is AFK Right Now! Cool'

Cuestiones relacionadas