La mejor manera de eliminar la puntuación de una cadena


639

Parece que debería haber una forma más simple que:

import string
s = "string. With. Punctuation?" # Sample string 
out = s.translate(string.maketrans("",""), string.punctuation)

¿Esta ahí?


3
Me parece bastante sencillo. por que lo quieres cambiar? Si quieres que sea más fácil, simplemente envuelve lo que acabas de escribir en una función.
Hannes Ovrén

2
Bueno, parecía un poco hacking estar usando un efecto secundario de str.translate para hacer el trabajo. Estaba pensando que podría haber algo más como str.strip (caracteres) que funcionaba en toda la cadena en lugar de solo los límites que me había perdido.
Lawrence Johnston el

2
Depende de los datos también. Usar esto en datos donde hay nombres de servidor con guiones bajos como parte del nombre (bastante común en algunos lugares) podría ser malo. Solo asegúrese de conocer los datos y lo que contienen, o podría terminar con un subconjunto del problema de clbuttic.
EBGreen

54
Depende también de lo que llames puntuación. " The temperature in the O'Reilly & Arbuthnot-Smythe server's main rack is 40.5 degrees." contiene exactamente UN carácter de puntuación, el segundo "."
John Machin

37
Me sorprende que nadie mencione que string.punctuationno incluye puntuación en inglés. Estoy pensando en。 ,!? : × “” 〟, y así sucesivamente.
Clément

Respuestas:


930

Desde una perspectiva de eficiencia, no vas a vencer

s.translate(None, string.punctuation)

Para versiones superiores de Python use el siguiente código:

s.translate(str.maketrans('', '', string.punctuation))

Realiza operaciones de cadena sin formato en C con una tabla de búsqueda: no hay mucho que supere eso, sino escribir su propio código C.

Si la velocidad no es una preocupación, otra opción es:

exclude = set(string.punctuation)
s = ''.join(ch for ch in s if ch not in exclude)

Esto es más rápido que reemplazarlo con cada carácter, pero no funcionará tan bien como los enfoques de Python no puros como regexes o string.translate, como puede ver en los tiempos a continuación. Para este tipo de problema, vale la pena hacerlo al nivel más bajo posible.

Código de tiempo:

import re, string, timeit

s = "string. With. Punctuation"
exclude = set(string.punctuation)
table = string.maketrans("","")
regex = re.compile('[%s]' % re.escape(string.punctuation))

def test_set(s):
    return ''.join(ch for ch in s if ch not in exclude)

def test_re(s):  # From Vinko's solution, with fix.
    return regex.sub('', s)

def test_trans(s):
    return s.translate(table, string.punctuation)

def test_repl(s):  # From S.Lott's solution
    for c in string.punctuation:
        s=s.replace(c,"")
    return s

print "sets      :",timeit.Timer('f(s)', 'from __main__ import s,test_set as f').timeit(1000000)
print "regex     :",timeit.Timer('f(s)', 'from __main__ import s,test_re as f').timeit(1000000)
print "translate :",timeit.Timer('f(s)', 'from __main__ import s,test_trans as f').timeit(1000000)
print "replace   :",timeit.Timer('f(s)', 'from __main__ import s,test_repl as f').timeit(1000000)

Esto da los siguientes resultados:

sets      : 19.8566138744
regex     : 6.86155414581
translate : 2.12455511093
replace   : 28.4436721802

27
Gracias por la información sobre el tiempo, estaba pensando en hacer algo así, pero el tuyo está mejor escrito que cualquier cosa que hubiera hecho y ahora puedo usarlo como plantilla para cualquier código de tiempo futuro que quiera escribir :).
Lawrence Johnston el

29
Gran respuesta. Puede simplificarlo quitando la tabla. Los documentos dicen: "establezca el argumento de la tabla en Ninguno para las traducciones que solo eliminan caracteres" ( docs.python.org/library/stdtypes.html#str.translate )
Alexandros Marinos

3
Vale la pena señalar también que translate () se comporta de manera diferente para los objetos str y unicode, por lo que debe asegurarse de que siempre está trabajando con el mismo tipo de datos, pero el enfoque en esta respuesta funciona igualmente bien para ambos, lo cual es útil.
Richard J

36
En Python3, ¿ table = string.maketrans("","")debería reemplazarse con table = str.maketrans({key: None for key in string.punctuation})?
SparkAndShine

19
¡Actualizar la discusión, a partir de Python 3.6, regexes ahora el método más eficiente! Es casi 2 veces más rápido que traducir. Además, ¡los juegos y el reemplazo ya no son tan malos! Ambos están mejorados por más de un factor de 4 :)
Ryan Soklaski

143

Las expresiones regulares son lo suficientemente simples, si las conoce.

import re
s = "string. With. Punctuation?"
s = re.sub(r'[^\w\s]','',s)

44
@Outlier Explicación: reemplaza no caracteres de palabra (^) o espacios con la cadena vacía. Sin embargo, tenga cuidado, el \ w coincide con el guión bajo demasiado generalmente, por ejemplo.
Matthias

44
@SIslam Creo que funcionará con Unicode con el conjunto de banderas Unicode, es decir s = re.sub(r'[^\w\s]','',s, re.UNICODE). Al probarlo con Python 3 en Linux, funciona incluso sin la bandera con letras tamil, தமிழ்.
Matthias

@Matthias Probé el código con Python 3.6.5 en Mac, la salida de letras Tamil se ve un poco diferente, la entrada தமிழ் se convierte en தமழ. No tengo conocimiento sobre Tamil, no estoy seguro de si eso se espera.
Shiouming

71

Para la conveniencia del uso, resumo la nota de puntuación de rayas de una cadena tanto en Python 2 como en Python 3. Consulte otras respuestas para obtener una descripción detallada.


Python 2

import string

s = "string. With. Punctuation?"
table = string.maketrans("","")
new_s = s.translate(table, string.punctuation)      # Output: string without punctuation

Python 3

import string

s = "string. With. Punctuation?"
table = str.maketrans(dict.fromkeys(string.punctuation))  # OR {key: None for key in string.punctuation}
new_s = s.translate(table)                          # Output: string without punctuation

51
myString.translate(None, string.punctuation)

44
Ah, probé esto pero no funciona en todos los casos. myString.translate (string.maketrans ("", ""), string.punctuation) funciona bien.
Aidan Kane el

12
Tenga stren cuenta que para Python 3 y unicodePython 2, el deletecharsargumento no es compatible.
agf

44
myString.translate (string.maketrans ("", ""), string.punctuation) NO funcionará con cadenas Unicode (descubierto de la manera difícil)
Marc Maxmeister

44
TypeError: translate() takes exactly one argument (2 given):(
Brian Tingle

3
@BrianTingle: mira el código de Python 3 en mi comentario (pasa un argumento). Siga el enlace para ver el código de Python 2 que funciona con Unicode y su adaptación de Python 3
jfs

29

Usualmente uso algo como esto:

>>> s = "string. With. Punctuation?" # Sample string
>>> import string
>>> for c in string.punctuation:
...     s= s.replace(c,"")
...
>>> s
'string With Punctuation'

2
Un afeado de una sola línea: reduce(lambda s,c: s.replace(c, ''), string.punctuation, s).
jfs

1
genial, sin embargo, no elimina algunas fluctuaciones como el guión más largo
Vladimir Stazhilov

25

string.punctuationes solo ASCII ! Una forma más correcta (pero también mucho más lenta) es usar el módulo unicodedata:

# -*- coding: utf-8 -*-
from unicodedata import category
s = u'String — with -  «punctation »...'
s = ''.join(ch for ch in s if category(ch)[0] != 'P')
print 'stripped', s

También puede generalizar y eliminar otros tipos de caracteres:

''.join(ch for ch in s if category(ch)[0] not in 'SP')

También eliminará caracteres como los ~*+§$que pueden o no ser "puntuación" dependiendo del punto de vista de cada uno.



Desafortunadamente, cosas como ~no son parte de la categoría de puntuación. También debe probar la categoría Símbolos.
CJ Jackson

24

No necesariamente más simple, pero de una manera diferente, si está más familiarizado con la familia re.

import re, string
s = "string. With. Punctuation?" # Sample string 
out = re.sub('[%s]' % re.escape(string.punctuation), '', s)

1
Funciona porque string.punctuation tiene la secuencia, -. en orden apropiado, ascendente, sin espacios, ASCII. Si bien Python tiene este derecho, cuando intenta utilizar un subconjunto de string.punctuation, puede ser un obstáculo para la sorpresa "-".
S.Lott

2
En realidad, todavía está mal. La secuencia "\]" se trata como un escape (casualmente no se cierra el], evitando otro error), pero deja \ sin escapar. Debe usar re.escape (string.punctuation) para evitar esto.
Brian

1
Sí, lo omití porque funcionó para el ejemplo para mantener las cosas simples, pero tiene razón en que debería incorporarse.
Vinko Vrsalovic

13

Para los valores de Python 3 stro Python 2 unicode, str.translate()solo toma un diccionario; los puntos de código (enteros) se buscan en esa asignación y Nonese elimina todo lo asignado .

Para eliminar (¿alguna?) Puntuación, entonces use:

import string

remove_punct_map = dict.fromkeys(map(ord, string.punctuation))
s.translate(remove_punct_map)

El dict.fromkeys()método de clase hace que sea trivial crear la asignación, estableciendo todos los valores en Nonefunción de la secuencia de claves.

Para eliminar toda la puntuación, no solo la puntuación ASCII, su tabla debe ser un poco más grande; ver la respuesta de JF Sebastian (versión Python 3):

import unicodedata
import sys

remove_punct_map = dict.fromkeys(i for i in range(sys.maxunicode)
                                 if unicodedata.category(chr(i)).startswith('P'))

Para soportar Unicode, string.punctuationno es suficiente. Ver mi respuesta
jfs

@JFSebastian: de hecho, mi respuesta fue simplemente usar los mismos caracteres que el más votado. Se agregó una versión de Python 3 de su tabla.
Martijn Pieters

la respuesta mejor votada solo funciona para cadenas ascii. Su respuesta reclama explícitamente el soporte Unicode.
jfs

1
@JFSebastian: funciona para cadenas Unicode. Despoja la puntuación ASCII. Nunca afirmé que elimina todos los signos de puntuación. :-) El objetivo era proporcionar la técnica correcta para los unicodeobjetos frente a los objetos de Python 2 str.
Martijn Pieters

12

string.punctuationpierde montones de signos de puntuación que se usan comúnmente en el mundo real. ¿Qué tal una solución que funciona para la puntuación no ASCII?

import regex
s = u"string. With. Some・Really Weird、Non?ASCII。 「(Punctuation)」?"
remove = regex.compile(ur'[\p{C}|\p{M}|\p{P}|\p{S}|\p{Z}]+', regex.UNICODE)
remove.sub(u" ", s).strip()

Personalmente, creo que esta es la mejor manera de eliminar la puntuación de una cadena en Python porque:

  • Elimina todos los signos de puntuación Unicode.
  • Es fácilmente modificable, por ejemplo, puede eliminar el \{S}si desea eliminar la puntuación, pero mantener símbolos como $.
  • Puede ser realmente específico sobre lo que desea conservar y lo que desea eliminar, por ejemplo \{Pd}, solo eliminará guiones.
  • Esta expresión regular también normaliza los espacios en blanco. Asigna pestañas, retornos de carro y otras rarezas a espacios agradables y únicos.

Utiliza las propiedades de caracteres Unicode, sobre las que puede leer más en Wikipedia .


9

No he visto esta respuesta todavía. Solo usa una expresión regular; elimina todos los caracteres además de los caracteres de palabra ( \w) y los caracteres de número ( \d), seguido de un carácter de espacio en blanco ( \s):

import re
s = "string. With. Punctuation?" # Sample string 
out = re.sub(ur'[^\w\d\s]+', '', s)

1
\des redundante ya que es un subconjunto de \w.
blhsing

¿Los caracteres numéricos se consideran un subconjunto de caracteres de Word? Pensé que un personaje de Word era cualquier personaje que pudiera construir una palabra real, por ejemplo, a-zA-Z?
Blairg23

Sí, una "palabra" en expresiones regulares incluye alfabetos, números y guiones bajos. Consulte la descripción \wen la documentación: docs.python.org/3/library/re.html
blhsing

8

Aquí hay una línea para Python 3.5:

import string
"l*ots! o(f. p@u)n[c}t]u[a'ti\"on#$^?/".translate(str.maketrans({a:None for a in string.punctuation}))

7

Esta podría no ser la mejor solución, sin embargo, así es como lo hice.

import string
f = lambda x: ''.join([i for i in x if i not in string.punctuation])

6

Aquí hay una función que escribí. No es muy eficiente, pero es simple y puede agregar o eliminar cualquier puntuación que desee:

def stripPunc(wordList):
    """Strips punctuation from list of words"""
    puncList = [".",";",":","!","?","/","\\",",","#","@","$","&",")","(","\""]
    for punc in puncList:
        for word in wordList:
            wordList=[word.replace(punc,'') for word in wordList]
    return wordList

5
import re
s = "string. With. Punctuation?" # Sample string 
out = re.sub(r'[^a-zA-Z0-9\s]', '', s)

Parece que eso solo funcionaría para los caracteres ASCII.
avirr

5

Solo como una actualización, reescribí el ejemplo de @Brian en Python 3 e hice cambios para mover el paso de compilación de expresiones regulares dentro de la función. Mi pensamiento aquí era cronometrar cada paso necesario para que la función funcionara. Tal vez está utilizando la informática distribuida y no puede tener un objeto regex compartido entre sus trabajadores y necesita tener un re.compilepaso en cada trabajador. Además, tenía curiosidad por cronometrar dos implementaciones diferentes de maketrans para Python 3

table = str.maketrans({key: None for key in string.punctuation})

vs

table = str.maketrans('', '', string.punctuation)

Además, agregué otro método para usar set, donde aprovecho la función de intersección para reducir el número de iteraciones.

Este es el código completo:

import re, string, timeit

s = "string. With. Punctuation"


def test_set(s):
    exclude = set(string.punctuation)
    return ''.join(ch for ch in s if ch not in exclude)


def test_set2(s):
    _punctuation = set(string.punctuation)
    for punct in set(s).intersection(_punctuation):
        s = s.replace(punct, ' ')
    return ' '.join(s.split())


def test_re(s):  # From Vinko's solution, with fix.
    regex = re.compile('[%s]' % re.escape(string.punctuation))
    return regex.sub('', s)


def test_trans(s):
    table = str.maketrans({key: None for key in string.punctuation})
    return s.translate(table)


def test_trans2(s):
    table = str.maketrans('', '', string.punctuation)
    return(s.translate(table))


def test_repl(s):  # From S.Lott's solution
    for c in string.punctuation:
        s=s.replace(c,"")
    return s


print("sets      :",timeit.Timer('f(s)', 'from __main__ import s,test_set as f').timeit(1000000))
print("sets2      :",timeit.Timer('f(s)', 'from __main__ import s,test_set2 as f').timeit(1000000))
print("regex     :",timeit.Timer('f(s)', 'from __main__ import s,test_re as f').timeit(1000000))
print("translate :",timeit.Timer('f(s)', 'from __main__ import s,test_trans as f').timeit(1000000))
print("translate2 :",timeit.Timer('f(s)', 'from __main__ import s,test_trans2 as f').timeit(1000000))
print("replace   :",timeit.Timer('f(s)', 'from __main__ import s,test_repl as f').timeit(1000000))

Estos son mis resultados:

sets      : 3.1830138750374317
sets2      : 2.189873124472797
regex     : 7.142953420989215
translate : 4.243278483860195
translate2 : 2.427158243022859
replace   : 4.579746678471565

4
>>> s = "string. With. Punctuation?"
>>> s = re.sub(r'[^\w\s]','',s)
>>> re.split(r'\s*', s)


['string', 'With', 'Punctuation']

2
Edite con más información. Se desaconsejan las respuestas de solo código y "pruebe esto", ya que no contienen contenido que se pueda buscar y no explican por qué alguien debería "probar esto".
Paritosh

4

Aquí hay una solución sin expresiones regulares.

import string

input_text = "!where??and!!or$$then:)"
punctuation_replacer = string.maketrans(string.punctuation, ' '*len(string.punctuation))    
print ' '.join(input_text.translate(punctuation_replacer).split()).strip()

Output>> where and or then
  • Reemplaza los signos de puntuación con espacios
  • Reemplace múltiples espacios entre palabras con un solo espacio
  • Elimine los espacios finales, si los hay con strip ()

4

Una frase podría ser útil en casos no muy estrictos:

''.join([c for c in s if c.isalnum() or c.isspace()])

2
#FIRST METHOD
#Storing all punctuations in a variable    
punctuation='!?,.:;"\')(_-'
newstring='' #Creating empty string
word=raw_input("Enter string: ")
for i in word:
     if(i not in punctuation):
                  newstring+=i
print "The string without punctuation is",newstring

#SECOND METHOD
word=raw_input("Enter string: ")
punctuation='!?,.:;"\')(_-'
newstring=word.translate(None,punctuation)
print "The string without punctuation is",newstring


#Output for both methods
Enter string: hello! welcome -to_python(programming.language)??,
The string without punctuation is: hello welcome topythonprogramminglanguage

2
with open('one.txt','r')as myFile:

    str1=myFile.read()

    print(str1)


    punctuation = ['(', ')', '?', ':', ';', ',', '.', '!', '/', '"', "'"] 

for i in punctuation:

        str1 = str1.replace(i," ") 
        myList=[]
        myList.extend(str1.split(" "))
print (str1) 
for i in myList:

    print(i,end='\n')
    print ("____________")

0

¿Por qué ninguno de ustedes usa esto?

 ''.join(filter(str.isalnum, s)) 

¿Demasiado lento?


Tenga en cuenta que esto también eliminará espacios.
Georgy

0

Considerando unicode. Código verificado en python3.

from unicodedata import category
text = 'hi, how are you?'
text_without_punc = ''.join(ch for ch in text if not category(ch).startswith('P'))

-1

Eliminar palabras de detención del archivo de texto usando Python

print('====THIS IS HOW TO REMOVE STOP WORS====')

with open('one.txt','r')as myFile:

    str1=myFile.read()

    stop_words ="not", "is", "it", "By","between","This","By","A","when","And","up","Then","was","by","It","If","can","an","he","This","or","And","a","i","it","am","at","on","in","of","to","is","so","too","my","the","and","but","are","very","here","even","from","them","then","than","this","that","though","be","But","these"

    myList=[]

    myList.extend(str1.split(" "))

    for i in myList:

        if i not in stop_words:

            print ("____________")

            print(i,end='\n')

-2

Me gusta usar una función como esta:

def scrub(abc):
    while abc[-1] is in list(string.punctuation):
        abc=abc[:-1]
    while abc[0] is in list(string.punctuation):
        abc=abc[1:]
    return abc

1
Esto es quitar caracteres del principio y del final; utilizar abc.strip(string.punctuation)en su lugar para eso. No eliminará tales caracteres en el medio .
Martijn Pieters
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.