2009-02-17 14 views
6

tengo una cadena en el formato:Separación de cadenas en el formato requerido, manera Pythonic? (Con o w/o expresiones regulares)

t='@abc @def Hello this part is text' 

quiero conseguir esto:

l=["abc", "def"] 
s='Hello this part is text' 

me hizo esto:

a=t[t.find(' ',t.rfind('@')):].strip() 
s=t[:t.find(' ',t.rfind('@'))].strip() 
b=a.split('@') 
l=[i.strip() for i in b][1:] 

Se funciona en su mayor parte, pero falla cuando la parte de texto tiene la '@'. Por ejemplo, cuando:

t='@abc @def My email is [email protected]' 

falla. Los @ nombres están allí al principio y puede haber texto después de @names, que posiblemente contengan @.

Claramente, puedo agregar un espacio al inicio y encontrar la primera palabra sin '@'. Pero eso no parece una solución elegante.

¿Qué es una forma pitónica de resolver esto?

Respuesta

13

edificio sin vergüenza en el esfuerzo de MrTopf:

import re 
rx = re.compile("((?:@\w+ +)+)(.*)") 
t='@abc @def @xyz Hello this part is text and my email is [email protected]' 
a,s = rx.match(t).groups() 
l = re.split('[@ ]+',a)[1:-1] 
print l 
print s 

impresiones:

[ 'abc', 'def', 'xyz']
Hola esta parte es texto y mi correo electrónico es foo @licenciado en Letras.r


Justamente llamado a rendir cuentas por hasen j, quiero aclarar cómo funciona esto:

/@\w+ +/ 

coincide con una sola etiqueta - @ seguido por al menos un alfanumérico o _ seguido por al menos una personaje espacial + es codicioso, por lo que si hay más de un espacio, los agarrará a todos.

Para hacer coincidir cualquier número de estas etiquetas, necesitamos agregar un más (una o más cosas) al patrón para la etiqueta; por lo que necesitamos para agruparlo con los paréntesis:

/(@\w+ +)+/ 

el que empareja uno o más etiquetas-y, de ser codicioso, partidos todos ellos. Sin embargo, esos paréntesis, ahora violín alrededor con nuestros grupos de captura, por lo que deshacer que al convertirlos en un grupo anónimo:

/(?:@\w+ +)+/ 

Por último, hacemos que en un grupo de captura y añadir otro para barrer el resto:

/((?:@\w+ +)+)(.*)/ 

Una última ruptura para resumir:

((?:@\w+ +)+)(.*) 
(?:@\w+ +)+ 
( @\w+ +) 
    @\w+ + 

Nótese que en revie Al hacerlo, lo he mejorado, no era necesario que estuviera en un conjunto, y ahora permite espacios múltiples entre etiquetas. Gracias, hasen-j!

+0

gracias por extenderlo :-) Al principio no me resultó claro que puede tratarse de cualquier cantidad de palabras. Pero también tuve problemas para encontrar la sintaxis correcta para la expresión regular cuando lo intenté de nuevo en realidad. Entonces veo que el grupo anónimo está ahora adentro, lo tuve afuera. – MrTopf

+0

¿te molestarías en explicar la expresión regular? ¿Por qué encuentra un número variable de "etiquetas" o lo que sea que se llame a @thing? – hasen

+1

Bien jugado Sir. Gracias por la explicación completa. – bernie

3
[i.strip('@') for i in t.split(' ', 2)[:2]]  # for a fixed number of @def 
a = [i.strip('@') for i in t.split(' ') if i.startswith('@')] 
s = ' '.join(i for i in t.split(' ') if not i.startwith('@')) 
+0

Los elementos iniciales pueden ser cualquier cantidad. Esto no funciona –

+0

que no estaba especificado en su pregunta original, pero aquí tiene. – SilentGhost

3

También puede utilizar expresiones regulares:

import re 
rx = re.compile("@([\w]+) @([\w]+) (.*)") 
t='@abc @def Hello this part is text and my email is [email protected]' 
a,b,s = rx.match(t).groups() 

Pero todo esto depende de cómo sus datos puedan ser similar. Por lo tanto, es posible que deba ajustarlo. Lo que hace es básicamente crear grupos vía() y verificar lo que está permitido en ellos.

+0

OP dice que el número de @names es variable – SilentGhost

5

¿Qué tal esto:

  1. Dividir por el espacio.
  2. palabra foreach, consultar

    2.1. si la palabra comienza con @ y luego presione la primera lista

    2.2. de lo contrario, solo une las palabras restantes por espacios.

3

[edición: esto está llevando a cabo lo que se sugirió por Osama anterior]

Esto creará L basado en las variables @ desde el principio de la cadena, y luego una vez al no @ var es encontrado, solo agarra el resto de la cuerda.

t = '@one @two @three some text afterward with @ [email protected] [email protected]' 

words = t.split(' ')   # split into list of words based on spaces 
L = [] 
s = '' 
for i in range(len(words)): # go through each word 
    word = words[i] 
    if word[0] == '@':  # grab @'s from beginning of string 
     L.append(word[1:]) 
     continue 
    s = ' '.join(words[i:]) # put spaces back in 
    break     # you can ignore the rest of the words 

Usted puede refactorizar esto sea menos código, pero yo estoy tratando de hacer lo que está pasando obvia.

7
t='@abc @def Hello this part is text' 

words = t.split(' ') 

names = [] 
while words: 
    w = words.pop(0) 
    if w.startswith('@'): 
     names.append(w[1:]) 
    else: 
     break 

text = ' '.join(words) 

print names 
print text 
+0

¡Me gusta más esta solución que la mía! votado hasta –

+0

Se eliminará espacio extra entre las palabras, por lo que este podría no ser un efecto secundario deseado. –

1

Aquí es sólo otra variante que utiliza split() y no hay regexpes:

t='@abc @def My email is [email protected]' 
tags = [] 
words = iter(t.split()) 

# iterate over words until first non-tag word 
for w in words: 
    if not w.startswith("@"): 
    # join this word and all the following 
    s = w + " " + (" ".join(words)) 
    break 
    tags.append(w[1:]) 
else: 
    s = "" # handle string with only tags 

print tags, s 

He aquí una corta pero tal vez una versión críptica bits que utiliza una expresión regular para encontrar el primer espacio seguido de un no @ character:

import re 
t = '@abc @def My email is [email protected] @extra bye' 
m = re.search(r"\s([^@].*)$", t) 
tags = [tag[1:] for tag in t[:m.start()].split()] 
s = m.group(1) 
print tags, s # ['abc', 'def'] My email is [email protected] @extra bye 

Esto no funciona correctamente si no hay etiquetas o no hay texto. El formato no está especificado. Tendrá que proporcionar más casos de prueba para validar.

Cuestiones relacionadas