web-dev-qa-db-fra.com

Meilleur moyen de supprimer la ponctuation d'une chaîne en Python

Il semble qu'il devrait y avoir un moyen plus simple que:

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

Y a-t-il?

515

Du point de vue de l'efficacité, vous n'allez pas battre

s.translate(None, string.punctuation)

Pour les versions supérieures de Python, utilisez le code suivant:

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

Il effectue des opérations de chaîne brutes en C avec une table de correspondance - il n'y a pas grand-chose qui batte celui-ci mais écrit votre propre code C.

Si la vitesse ne vous inquiète pas, une autre option est:

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

Ceci est plus rapide qu'à chaque caractère, mais ne fonctionne pas aussi bien que les approches python non pures telles que les expressions rationnelles ou string.translate, comme vous pouvez le constater avec les timings ci-dessous. Pour ce type de problème, le faire à un niveau aussi bas que possible rapporte.

Code de chronométrage:

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)

Cela donne les résultats suivants:

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

Les expressions régulières sont assez simples, si vous les connaissez.

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

Dans le code ci-dessus, nous substituons (re.sub) tous les NON [caractères alphanumériques (\ w) et les espaces (\ s)] par une chaîne vide.
Par conséquent . et ? la ponctuation ne sera pas présente dans la variable 's' après avoir exécuté la variable s avec regex.

107
Eratosthenes

Pour la commodité de l’utilisation, je résume la note de ponctuation de striping d’une chaîne dans Python 2 et Python 3. Veuillez vous reporter à d’autres réponses pour une description détaillée.


Python 2

import string

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

Python

import string

s = "string. With. Punctuation?"
table = str.maketrans({key: None for key in string.punctuation})
new_s = s.translate(table)                          # Output: string without punctuation
58
SparkAndShine
myString.translate(None, string.punctuation)
51
pyrou

J'utilise habituellement quelque chose comme ça:

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

string.punctuation est ASCII seulement! Une méthode plus correcte (mais aussi beaucoup plus lente) consiste à utiliser le module 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
22
Björn Lindqvist

Pas nécessairement plus simple, mais d'une manière différente, si vous connaissez mieux la famille re.

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

string.punctuation manque des charges de signes de ponctuation couramment utilisés dans le monde réel. Que diriez-vous d'une solution qui fonctionne pour la ponctuation non-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()

Personnellement, je pense que c'est le meilleur moyen de supprimer la ponctuation d'une chaîne en Python car:

  • Il supprime toute ponctuation Unicode
  • Il est facilement modifiable, par exemple vous pouvez supprimer le \{S} si vous souhaitez supprimer la ponctuation, tout en conservant des symboles tels que $.
  • Vous pouvez obtenir des informations très précises sur ce que vous souhaitez conserver et ce que vous souhaitez supprimer. Par exemple, \{Pd} ne supprimera que les tirets.
  • Cette expression régulière normalise également les espaces. Il mappe les onglets, les retours chariots et autres curiosités vers Nice, des espaces simples.

Ceci utilise les propriétés de caractère Unicode, qui vous pouvez en savoir plus sur Wikipedia .

12
Zach

Pour Python 3 strou Python 2 unicodename__, str.translate() ne prend qu'un dictionnaire; Les points de code (entiers) sont recherchés dans ce mappage et tout ce qui est mappé à Noneest supprimé.

Pour supprimer (certains?) Ponctuation, utilisez:

import string

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

La méthode dict.fromkeys() class rend la création du mappage facile, en définissant toutes les valeurs sur Noneen fonction de la séquence de clés.

Pour supprimer toute la ponctuation, et pas seulement ASCII ponctuation, votre tableau doit être un peu plus grand; voir réponse de J.F. Sebastian (version 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'))
12
Martijn Pieters

Ce n'est peut-être pas la meilleure solution, mais voici comment je l'ai fait.

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

Voici une fonction que j'ai écrite. Ce n'est pas très efficace, mais c'est simple et vous pouvez ajouter ou supprimer toute ponctuation que vous désirez:

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
6
Dr.Tautology

Je n'ai pas encore vu cette réponse. Il suffit d'utiliser un regex; il supprime tous les caractères autres que les mots Word (\w) et les caractères numériques (\d), suivis d'un caractère blanc (\s):

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

Voici un one-liner pour 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}))
6
Tim P

À titre de mise à jour, j’ai réécrit l’exemple @Brian dans Python 3 et ya apporté des modifications pour déplacer l’étape de compilation regex à l’intérieur de la fonction. Ma pensée était de chronométrer chaque étape nécessaire pour que la fonction fonctionne. Peut-être utilisez-vous l'informatique distribuée et ne pouvez-vous pas partager un objet regex entre vos travailleurs et devez-vous avoir l'étape re.compile à chaque travailleur? Aussi, j'étais curieux de chronométrer deux implémentations différentes de maketrans pour Python 3

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

contre

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

De plus, j'ai ajouté une autre méthode pour utiliser set, où je tire parti de la fonction d'intersection pour réduire le nombre d'itérations.

C'est le code complet:

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))

Voici mes résultats:

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

Voici une solution sans regex.

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
  • Remplace les ponctuations par des espaces
  • Remplacer plusieurs espaces entre les mots par un seul espace
  • Supprimer les espaces de fin, le cas échéant avec strip ()
4
ngub05
import re
s = "string. With. Punctuation?" # Sample string 
out = re.sub(r'[^a-zA-Z0-9\s]', '', s)
3
Haythem HADHAB
>>> s = "string. With. Punctuation?"
>>> s = re.sub(r'[^\w\s]','',s)
>>> re.split(r'\s*', s)


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

Un one-liner pourrait être utile dans des cas peu sévères:

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

Effectuez une recherche et remplacez à l’aide des fonctions regex, comme indiqué ici. . Si vous devez effectuer l'opération à plusieurs reprises, vous pouvez conserver une copie compilée du motif regex (votre ponctuation), ce qui accélérera un peu les choses.

1
Dana the Sane
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 ("____________")
#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
1

Pourquoi aucun de vous ne l'utilise?

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

Trop lent?

0
Dehua Li