una - separar python




Dividir cadenas con múltiples delimitadores? (20)

Aquí está la respuesta con alguna explicación.

st = "Hey, you - what are you doing here!?"

# replace all the non alpha-numeric with space and then join.
new_string = ''.join([x.replace(x, ' ') if not x.isalnum() else x for x in st])
# output of new_string
'Hey  you  what are you doing here  '

# str.split() will remove all the empty string if separator is not provided
new_list = new_string.split()

# output of new_list
['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

# we can join it to get a complete string without any non alpha-numeric character
' '.join(new_list)
# output
'Hey you what are you doing'

o en una línea, podemos hacer esto:

(''.join([x.replace(x, ' ') if not x.isalnum() else x for x in st])).split()

# output
['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

respuesta actualizada

Creo que lo que quiero hacer es una tarea bastante común, pero no he encontrado ninguna referencia en la web. Tengo texto, con puntuación, y quiero una lista de las palabras.

"Hey, you - what are you doing here!?"

debiera ser

['hey', 'you', 'what', 'are', 'you', 'doing', 'here']

Pero str.split() Python solo funciona con un argumento ... Así que tengo todas las palabras con la puntuación después de dividirme con espacios en blanco. ¿Algunas ideas?


Aquí está mi ir a una división con múltiples eliminadores:

def msplit( str, delims ):
  w = ''
  for z in str:
    if z not in delims:
        w += z
    else:
        if len(w) > 0 :
            yield w
        w = ''
  if len(w) > 0 :
    yield w

Cree una función que tome como entrada dos cadenas (la cadena de origen que se dividirá y la cadena de delimitadores de la lista dividida) y generará una lista de palabras divididas:

def split_string(source, splitlist):
    output = []  # output list of cleaned words
    atsplit = True
    for char in source:
        if char in splitlist:
            atsplit = True
        else:
            if atsplit:
                output.append(char)  # append new word after split
                atsplit = False
            else: 
                output[-1] = output[-1] + char  # continue copying characters until next split
    return output

Creo que la siguiente es la mejor respuesta para satisfacer sus necesidades:

\W+ puede ser adecuado para este caso, pero puede no serlo para otros casos.

filter(None, re.compile('[ |,|\-|!|?]').split( "Hey, you - what are you doing here!?")

En lugar de usar una función re módulo re.split, puede obtener el mismo resultado utilizando el método series.str.split de pandas.

Primero, cree una serie con la cadena anterior y luego aplique el método a la serie.

thestring = pd.Series("Hey, you - what are you doing here!?") thestring.str.split(pat = ',|-')

el parámetro pat toma los delimitadores y devuelve la cadena dividida como una matriz. Aquí los dos delimitadores se pasan usando un | (u operador). La salida es la siguiente:

[Hey, you , what are you doing here!?]


En primer lugar, no creo que su intención sea utilizar la puntuación como delimitadores en las funciones de división. Su descripción sugiere que simplemente desea eliminar la puntuación de las cadenas resultantes.

Me encuentro con esto con bastante frecuencia, y mi solución habitual no requiere re.

Función lambda de una línea con comprensión de lista:

(requiere import string ):

split_without_punc = lambda text : [word.strip(string.punctuation) for word in 
    text.split() if word.strip(string.punctuation) != '']

# Call function
split_without_punc("Hey, you -- what are you doing?!")
# returns ['Hey', 'you', 'what', 'are', 'you', 'doing']


Función (tradicional)

Como una función tradicional, esto sigue siendo solo dos líneas con una lista de comprensión (además de la import string ):

def split_without_punctuation2(text):

    # Split by whitespace
    words = text.split()

    # Strip punctuation from each word
    return [word.strip(ignore) for word in words if word.strip(ignore) != '']

split_without_punctuation2("Hey, you -- what are you doing?!")
# returns ['Hey', 'you', 'what', 'are', 'you', 'doing']

También naturalmente dejará intactas las contracciones y las palabras con guiones. Siempre puede usar text.replace("-", " ") para convertir los guiones en espacios antes de la división.

Función general sin Lambda o comprensión de lista

Para una solución más general (donde puede especificar los caracteres a eliminar), y sin una lista de comprensión, obtendrá:

def split_without(text: str, ignore: str) -> list:

    # Split by whitespace
    split_string = text.split()

    # Strip any characters in the ignore string, and ignore empty strings
    words = []
    for word in split_string:
        word = word.strip(ignore)
        if word != '':
            words.append(word)

    return words

# Situation-specific call to general function
import string
final_text = split_without("Hey, you - what are you doing?!", string.punctuation)
# returns ['Hey', 'you', 'what', 'are', 'you', 'doing']

Por supuesto, también puede generalizar la función lambda a cualquier cadena de caracteres especificada.


Heres mi toma en ello ...

def split_string(source,splitlist):
    splits = frozenset(splitlist)
    l = []
    s1 = ""
    for c in source:
        if c in splits:
            if s1:
                l.append(s1)
                s1 = ""
        else:
            print s1
            s1 = s1 + c
    if s1:
        l.append(s1)
    return l

>>>out = split_string("First Name,Last Name,Street Address,City,State,Zip Code",",")
>>>print out
>>>['First Name', 'Last Name', 'Street Address', 'City', 'State', 'Zip Code']

Me estoy reencontrando con Python y necesitaba lo mismo. La solución de Findall puede ser mejor, pero se me ocurrió esto:

tokens = [x.strip() for x in data.split(',')]

Me gusta el replace() la mejor manera. El siguiente procedimiento cambia todos los separadores definidos en una lista splitlist cadenas al primer separador en lista splitlist y luego divide el texto en ese único separador. También cuenta si la lista splitlist es una cadena vacía. Devuelve una lista de palabras, sin cadenas vacías.

def split_string(text, splitlist):
    for sep in splitlist:
        text = text.replace(sep, splitlist[0])
    return filter(None, text.split(splitlist[0])) if splitlist else [text]

Otra forma de lograrlo es usar el kit de herramientas de lenguaje natural ( nltk ).

import nltk
data= "Hey, you - what are you doing here!?"
word_tokens = nltk.tokenize.regexp_tokenize(data, r'\w+')
print word_tokens

Esto imprime: ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

El mayor inconveniente de este método es que necesita instalar el paquete nltk .

Los beneficios son que puedes hacer muchas cosas divertidas con el resto del paquete nltk una vez que obtengas tus tokens.


Otra forma, sin expresiones regulares.

import string
punc = string.punctuation
thestring = "Hey, you - what are you doing here!?"
s = list(thestring)
''.join([o for o in s if not o in punc]).split()

Primero, quiero estar de acuerdo con los demás en que las soluciones basadas en str.translate(...) regulares o str.translate(...) son más str.translate(...) . Para mi caso de uso, el desempeño de esta función no fue significativo, por lo que quise agregar ideas que consideré con ese criterio.

Mi objetivo principal era generalizar las ideas de algunas de las otras respuestas en una solución que podría funcionar para cadenas que contengan más que palabras de expresiones regulares (es decir, incluir en la lista negra el subconjunto explícito de caracteres de puntuación frente a caracteres de palabras de la lista blanca).

Tenga en cuenta que, en cualquier enfoque, también se podría considerar el uso de string.punctuation en lugar de una lista definida manualmente.

Opción 1 - re.sub

Me sorprendió ver que no hay respuesta hasta ahora utiliza re.sub(...) . Me parece un enfoque simple y natural para este problema.

import re

my_str = "Hey, you - what are you doing here!?"

words = re.split(r'\s+', re.sub(r'[,\-!?]', ' ', my_str).strip())

En esta solución, re.sub(...) la llamada a re.sub(...) inside re.split(...) , pero si el rendimiento es crítico, compilar la expresión regular fuera podría ser beneficioso, para mi caso de uso, la diferencia no fue Es significativo, así que prefiero la simplicidad y la legibilidad.

Opción 2 - str.replace

Estas son algunas líneas más, pero tiene la ventaja de ser expandible sin tener que verificar si necesita escapar de un determinado carácter en expresiones regulares.

my_str = "Hey, you - what are you doing here!?"

replacements = (',', '-', '!', '?')
for r in replacements:
    my_str = my_str.replace(r, ' ')

words = my_str.split()

Hubiera sido bueno poder asignar el str.replace a la cadena, pero no creo que se pueda hacer con cadenas inmutables, y si bien la asignación de una lista de caracteres funcionaría, ejecutar cada reemplazo contra cada carácter suena excesivo (Editar: vea la siguiente opción para un ejemplo funcional).

Opción 3 - functools.reduce

(En Python 2, reduce está disponible en el espacio de nombres global sin importarlo desde functools).

import functools

my_str = "Hey, you - what are you doing here!?"

replacements = (',', '-', '!', '?')
my_str = functools.reduce(lambda s, sep: s.replace(sep, ' '), replacements, my_str)
words = my_str.split()

Tantas respuestas, pero no puedo encontrar ninguna solución que haga lo que literalmente pide el título de las preguntas (división en varios posibles separadores; en cambio, muchas respuestas eliminan todo lo que no es una palabra, que es diferente). Así que aquí hay una respuesta a la pregunta en el título, que se basa en el módulo estándar y eficiente de Python:

>>> import re  # Will be splitting on: , <space> - ! ? :
>>> filter(None, re.split("[, \-!?:]+", "Hey, you - what are you doing here!?"))
['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

dónde:

  • el […] coincide con uno de los separadores que figuran en el interior,
  • la \- en la expresión regular está aquí para evitar la interpretación especial de - como un indicador de rango de caracteres (como en AZ ),
  • el + omite uno o más delimitadores (se podría omitir gracias al filter() , pero esto produciría innecesariamente cadenas vacías entre separadores emparejados), y
  • filter(None, …) elimina las cadenas vacías posiblemente creadas por separadores iniciales y finales (ya que las cadenas vacías tienen un valor booleano falso).

Este re.split() precisamente se "divide con varios separadores", como se solicita en el título de la pregunta.

Esta solución tampoco sufre problemas con los caracteres que no son ASCII en palabras (consulte el primer comentario de la respuesta de ghostdog74 ).

El módulo re es mucho más eficiente que hacer bucles y pruebas de Python "a mano".


Un caso donde las expresiones regulares están justificadas:

import re
DATA = "Hey, you - what are you doing here!?"
print re.findall(r"[\w']+", DATA)
# Prints ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

Usando Maketrans y Translate puedes hacerlo de manera fácil y ordenada.

import string
specials = ',.!?:;"()<>[]#$=-/'
trans = string.maketrans(specials, ' '*len(specials))
body = body.translate(trans)
words = body.strip().split()

Utilice reemplazar dos veces:

a = '11223FROM33344INTO33222FROM3344'
a.replace('FROM', ',,,').replace('INTO', ',,,').split(',,,')

resultados en:

['11223', '33344', '33222', '3344']

tengo el mismo problema que @ooboo y encontrar este tema @ ghostdog74 me inspiró, tal vez alguien encuentre útil mi solución

str1='adj:sg:nom:m1.m2.m3:pos'
splitat=':.'
''.join([ s if s not in splitat else ' ' for s in str1]).split()

ingresa algo en el lugar del espacio y divide usando el mismo carácter si no quieres dividir en los espacios.


re.split()

re.split (patrón, cadena [, maxsplit = 0])

Dividir cadena por las ocurrencias de patrón. Si se utilizan paréntesis de captura en el patrón, entonces el texto de todos los grupos en el patrón también se devuelve como parte de la lista resultante. Si maxsplit es distinto de cero, como máximo se producen las divisiones maxsplit, y el resto de la cadena se devuelve como el elemento final de la lista. (Nota de incompatibilidad: en la versión original de Python 1.5, se ignoró maxsplit. Esto se ha corregido en versiones posteriores).

>>> re.split('\W+', 'Words, words, words.')
['Words', 'words', 'words', '']
>>> re.split('(\W+)', 'Words, words, words.')
['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split('\W+', 'Words, words, words.', 1)
['Words', 'words, words.']

def get_words(s):
    l = []
    w = ''
    for c in s.lower():
        if c in '-!?,. ':
            if w != '': 
                l.append(w)
            w = ''
        else:
            w = w + c
    if w != '': 
        l.append(w)
    return l

Aquí está el uso:

>>> s = "Hey, you - what are you doing here!?"
>>> print get_words(s)
['hey', 'you', 'what', 'are', 'you', 'doing', 'here']

join = lambda x: sum(x,[])  # a.k.a. flatten1([[1],[2,3],[4]]) -> [1,2,3,4]
# ...alternatively...
join = lambda lists: [x for l in lists for x in l]

Entonces esto se convierte en un triplete:

fragments = [text]
for token in tokens:
    fragments = join(f.split(token) for f in fragments)

Explicación

Esto es lo que en Haskell se conoce como la mónada de la Lista. La idea detrás de la mónada es que una vez "en la mónada", usted "permanezca en la mónada" hasta que algo lo saque. Por ejemplo, en Haskell, digamos que asigna la función de range(n) -> [1,2,...,n] python sobre una Lista. Si el resultado es una Lista, se agregará a la Lista en el lugar, por lo que obtendríamos algo como map(range, [3,4,1]) -> [0,1,2,0,1,2,3,0] . Esto se conoce como map-append (o mappend, o tal vez algo así). La idea aquí es que tienes esta operación que estás aplicando (dividiendo en un token), y cada vez que lo haces, unes el resultado a la lista.

Puede abstraer esto en una función y tener tokens=string.punctuation de forma predeterminada.

Ventajas de este enfoque:

  • Este enfoque (a diferencia de los enfoques ingenuos basados ​​en expresiones regulares) puede funcionar con tokens de longitud arbitraria (lo que las expresiones regulares también pueden hacer con una sintaxis más avanzada).
  • No estás restringido a meros tokens; podría tener una lógica arbitraria en lugar de cada token, por ejemplo, uno de los "tokens" podría ser una función que se divide de acuerdo a cómo están los paréntesis anidados.






split