Der beste Weg, um Interpunktion von einer Zeichenfolge zu entfernen

635

Es scheint, dass es einen einfacheren Weg geben sollte als:

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

Gibt es?

Lawrence Johnston
quelle
3
Scheint mir ziemlich einfach zu sein. Warum willst du es ändern? Wenn Sie es einfacher haben möchten, verpacken Sie einfach das, was Sie gerade geschrieben haben, in eine Funktion.
Hannes Ovrén
2
Nun, es schien nur irgendwie hackisch zu sein, eine Art Nebeneffekt von str.translate zu verwenden, um die Arbeit zu erledigen. Ich dachte, es könnte mehr wie str.strip (Zeichen) geben, das auf der gesamten Zeichenfolge funktioniert, anstatt nur auf den Grenzen, die ich übersehen hatte.
Lawrence Johnston
2
Kommt auch auf die Daten an. Die Verwendung dieser Funktion für Daten, bei denen Servernamen mit Unterstrichen als Teil des Namens vorhanden sind (an einigen Stellen ziemlich häufig), kann schlecht sein. Stellen Sie nur sicher, dass Sie die Daten kennen und wissen, was sie enthalten, da sonst möglicherweise eine Teilmenge des Clbuttic-Problems auftritt.
EBGreen
54
Kommt auch darauf an, was du Interpunktion nennst. " The temperature in the O'Reilly & Arbuthnot-Smythe server's main rack is 40.5 degrees." enthält genau EIN Interpunktionszeichen, das zweite "."
John Machin
37
Ich bin überrascht, dass niemand erwähnt hat, der string.punctuationüberhaupt keine nicht-englische Zeichensetzung enthält. Ich denke an。 ,! : : × “” 〟und so weiter.
Clément

Antworten:

926

Aus Sicht der Effizienz werden Sie nicht schlagen

s.translate(None, string.punctuation)

Verwenden Sie für höhere Versionen von Python den folgenden Code:

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

Es führt rohe Zeichenfolgenoperationen in C mit einer Nachschlagetabelle durch - es gibt nicht viel, das das übertrifft, außer Ihren eigenen C-Code zu schreiben.

Wenn Geschwindigkeit keine Sorge ist, ist eine andere Option:

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

Dies ist schneller als das Ersetzen mit jedem Zeichen, funktioniert jedoch nicht so gut wie nicht reine Python-Ansätze wie Regexes oder string.translate, wie Sie aus den folgenden Zeitangaben ersehen können. Für diese Art von Problem zahlt es sich aus, es so niedrig wie möglich zu halten.

Timing-Code:

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)

Dies ergibt die folgenden Ergebnisse:

sets      : 19.8566138744
regex     : 6.86155414581
translate : 2.12455511093
replace   : 28.4436721802
Brian
quelle
27
Vielen Dank für die Timing-Informationen, ich habe darüber nachgedacht, so etwas selbst zu machen, aber deins ist besser geschrieben als alles, was ich getan hätte, und jetzt kann ich es als Vorlage für jeden zukünftigen Timing-Code verwenden, den ich schreiben möchte :).
Lawrence Johnston
29
Gute Antwort. Sie können es vereinfachen, indem Sie die Tabelle entfernen. In den Dokumenten heißt es: "Setzen Sie das Tabellenargument für Übersetzungen, bei denen nur Zeichen gelöscht werden, auf" Keine "( docs.python.org/library/stdtypes.html#str.translate )
Alexandros Marinos
3
Beachten Sie auch, dass sich translate () für str- und unicode-Objekte unterschiedlich verhält. Sie müssen also sicher sein, dass Sie immer mit demselben Datentyp arbeiten, aber der Ansatz in dieser Antwort funktioniert für beide gleich gut, was praktisch ist.
Richard J
36
Sollte in Python3 table = string.maketrans("","")durch table = str.maketrans({key: None for key in string.punctuation})? Ersetzt werden ?
SparkAndShine
18
Das Aktualisieren der Diskussion ab Python 3.6 regexist jetzt die effizienteste Methode! Es ist fast 2x schneller als übersetzen. Auch Sets und Ersetzen sind nicht mehr so ​​schlecht! Sie sind beide um mehr als den Faktor 4 verbessert :)
Ryan Soklaski
143

Reguläre Ausdrücke sind einfach genug, wenn Sie sie kennen.

import re
s = "string. With. Punctuation?"
s = re.sub(r'[^\w\s]','',s)
Eratosthenes
quelle
4
@Outlier Erläuterung: Ersetzt keine (^) Wortzeichen oder Leerzeichen durch die leere Zeichenfolge. Seien Sie jedoch vorsichtig, die \ w-Übereinstimmungen unterstreichen zum Beispiel zu häufig.
Matthias
4
@ Islam Ich denke, es wird mit Unicode mit gesetztem Unicode-Flag funktionieren, dh s = re.sub(r'[^\w\s]','',s, re.UNICODE). Wenn Sie es mit Python 3 unter Linux testen, funktioniert es auch ohne Flag mit tamilischen Buchstaben, தமிழ்.
Matthias
@Matthias Ich habe den Code mit Python 3.6.5 auf dem Mac ausprobiert. Die Ausgabe der tamilischen Buchstaben sieht etwas anders aus. Die Eingabe தமிழ் wird தமழ. Ich habe keine Kenntnisse über Tamil, nicht sicher, ob das erwartet wird.
Shiouming
70

Zur Vereinfachung der Verwendung fasse ich den Hinweis auf das Entfernen von Interpunktion aus einer Zeichenfolge in Python 2 und Python 3 zusammen. Eine ausführliche Beschreibung finden Sie in anderen Antworten.


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
SparkAndShine
quelle
51
myString.translate(None, string.punctuation)
Pyrou
quelle
4
Ah, ich habe es versucht, aber es funktioniert nicht in allen Fällen. myString.translate (string.maketrans ("", ""), string.punctuation) funktioniert einwandfrei.
Aidan Kane
12
Beachten Sie, dass strin Python 3 und unicodein Python 2 das deletecharsArgument nicht unterstützt wird.
agf
4
myString.translate (string.maketrans ("", ""), string.punctuation) funktioniert NICHT mit Unicode-Strings (auf die harte
Tour herausgefunden
44
TypeError: translate() takes exactly one argument (2 given):(
Brian Tingle
3
@BrianTingle: Sehen Sie sich den Python 3-Code in meinem Kommentar an (er übergibt ein Argument). Folgen Sie dem Link, um Python 2-Code zu sehen, der mit Unicode und seiner Python 3-Anpassung
jfs
29

Normalerweise benutze ich so etwas:

>>> s = "string. With. Punctuation?" # Sample string
>>> import string
>>> for c in string.punctuation:
...     s= s.replace(c,"")
...
>>> s
'string With Punctuation'
S.Lott
quelle
2
Ein hässlicher Einzeiler : reduce(lambda s,c: s.replace(c, ''), string.punctuation, s).
JFS
1
großartig, entfernt jedoch keine Schwankungen wie einen längeren Bindestrich
Vladimir Stazhilov
25

string.punctuationist nur ASCII ! Eine korrektere (aber auch viel langsamere) Methode ist die Verwendung des Unicodedata-Moduls:

# -*- 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

Sie können auch andere Zeichentypen verallgemeinern und entfernen:

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

Es werden auch Zeichen entfernt, ~*+§$die je nach Sichtweise eine "Interpunktion" sein können oder nicht.

Björn Lindqvist
quelle
3
Sie könnten:regex.sub(ur"\p{P}+", "", text)
jfs
Leider gehören Dinge wie ~nicht zur Kategorie Interpunktion. Sie müssen auch die Kategorie Symbole testen.
CJ Jackson
24

Nicht unbedingt einfacher, aber anders, wenn Sie mit der Re-Familie besser vertraut sind.

import re, string
s = "string. With. Punctuation?" # Sample string 
out = re.sub('[%s]' % re.escape(string.punctuation), '', s)
Vinko Vrsalovic
quelle
1
Funktioniert, weil string.punctuation die Sequenz - hat. in der richtigen, aufsteigenden, lückenlosen ASCII-Reihenfolge. Während Python dieses Recht hat, kann es beim Versuch, eine Teilmenge von string.punctuation zu verwenden, aufgrund der Überraschung "-" ein Show-Stopper sein.
S.Lott
2
Eigentlich ist es immer noch falsch. Die Sequenz "\]" wird als Escape behandelt (zufällig wird das] nicht geschlossen, um einen weiteren Fehler zu umgehen), bleibt jedoch unberührt. Sie sollten re.escape (string.punctuation) verwenden, um dies zu verhindern.
Brian
1
Ja, ich habe es weggelassen, weil es für das Beispiel funktioniert hat, um die Dinge einfach zu halten, aber Sie haben Recht, dass es aufgenommen werden sollte.
Vinko Vrsalovic
13

Für Python 3- stroder Python 2- unicodeWerte wird str.translate()nur ein Wörterbuch verwendet. Codepunkte (Ganzzahlen) werden in dieser Zuordnung nachgeschlagen und alles, was zugeordnet ist, Nonewird entfernt.

Verwenden Sie zum Entfernen von (einigen?) Satzzeichen:

import string

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

Die dict.fromkeys()Klassenmethode macht es einfach, das Mapping zu erstellen und alle Werte Nonebasierend auf der Tastenfolge festzulegen.

Um alle Interpunktionen zu entfernen , nicht nur die ASCII-Interpunktion, muss Ihre Tabelle etwas größer sein. siehe JF Sebastians Antwort (Python 3-Version):

import unicodedata
import sys

remove_punct_map = dict.fromkeys(i for i in range(sys.maxunicode)
                                 if unicodedata.category(chr(i)).startswith('P'))
Martijn Pieters
quelle
Die Unterstützung von Unicode string.punctuationreicht nicht aus. Siehe meine Antwort
jfs
@JFSebastian: In der Tat verwendete meine Antwort nur die gleichen Zeichen wie das am besten gewählte. Eine Python 3-Version Ihrer Tabelle wurde hinzugefügt.
Martijn Pieters
Die Antwort mit der höchsten Bewertung funktioniert nur für ASCII-Zeichenfolgen. Ihre Antwort beansprucht ausdrücklich die Unicode-Unterstützung.
JFS
1
@JFSebastian: Es funktioniert für Unicode-Zeichenfolgen. ASCII-Interpunktion wird entfernt. Ich habe nie behauptet, dass es alle Interpunktion entfernt. :-) Es ging darum, die richtige Technik für unicodeObjekte im Vergleich zu Python 2- strObjekten bereitzustellen .
Martijn Pieters
12

string.punctuationEs fehlen viele Satzzeichen, die in der realen Welt häufig verwendet werden. Wie wäre es mit einer Lösung, die für Nicht-ASCII-Interpunktion funktioniert?

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

Persönlich glaube ich, dass dies der beste Weg ist, um Interpunktion aus einer Zeichenfolge in Python zu entfernen, weil:

  • Es entfernt alle Unicode-Interpunktion
  • Es ist leicht zu ändern, z. B. können Sie die entfernen, \{S}wenn Sie Interpunktion entfernen möchten, aber Symbole wie beibehalten $.
  • Sie können genau festlegen, was Sie behalten möchten und was Sie entfernen möchten. Beispielsweise \{Pd}werden nur Bindestriche entfernt.
  • Diese Regex normalisiert auch Leerzeichen. Es ordnet Registerkarten, Wagenrückläufe und andere Kuriositäten schönen einzelnen Leerzeichen zu.

Hierbei werden Unicode-Zeicheneigenschaften verwendet, über die Sie auf Wikipedia mehr lesen können .

Zach
quelle
9

Ich habe diese Antwort noch nicht gesehen. Verwenden Sie einfach einen regulären Ausdruck. Es werden alle Zeichen außer Wortzeichen ( \w) und Zahlenzeichen ( \d) entfernt, gefolgt von einem Leerzeichen ( \s):

import re
s = "string. With. Punctuation?" # Sample string 
out = re.sub(ur'[^\w\d\s]+', '', s)
Blairg23
quelle
1
\dist redundant, da es sich um eine Teilmenge von handelt \w.
Blhsing
Zahlenzeichen werden als Teilmenge von Word-Zeichen betrachtet? Ich dachte, ein Wortzeichen wäre ein Zeichen, das ein echtes Wort konstruieren könnte, z. B. a-zA-Z?
Blairg23
Ja, ein "Wort" in Regex enthält Alphabete, Zahlen und Unterstriche. Bitte beachten Sie die Beschreibung \win der Dokumentation: docs.python.org/3/library/re.html
blhsing
8

Hier ist ein Einzeiler für 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}))
Tim P.
quelle
7

Dies ist möglicherweise nicht die beste Lösung, aber so habe ich es gemacht.

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

Hier ist eine Funktion, die ich geschrieben habe. Es ist nicht sehr effizient, aber es ist einfach und Sie können jede gewünschte Interpunktion hinzufügen oder entfernen:

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
Dr.Tautologie
quelle
5
import re
s = "string. With. Punctuation?" # Sample string 
out = re.sub(r'[^a-zA-Z0-9\s]', '', s)
Haythem HADHAB
quelle
Scheint so, als würde das nur für ASCII-Zeichen funktionieren.
Avirr
5

Nur als Update habe ich das @ Brian-Beispiel in Python 3 neu geschrieben und Änderungen daran vorgenommen, um den Regex-Kompilierungsschritt innerhalb der Funktion zu verschieben. Mein Gedanke hier war, jeden einzelnen Schritt zu planen, der erforderlich ist, damit die Funktion funktioniert. Möglicherweise verwenden Sie verteiltes Computing und können kein Regex-Objekt zwischen Ihren Mitarbeitern teilen. Sie müssen re.compilebei jedem Mitarbeiter einen Schritt ausführen. Außerdem war ich neugierig, zwei verschiedene Implementierungen von Maketrans für Python 3 zu planen

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

vs.

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

Außerdem habe ich eine weitere Methode zur Verwendung von set hinzugefügt, bei der ich die Schnittfunktion nutze, um die Anzahl der Iterationen zu reduzieren.

Dies ist der vollständige Code:

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

Das sind meine Ergebnisse:

sets      : 3.1830138750374317
sets2      : 2.189873124472797
regex     : 7.142953420989215
translate : 4.243278483860195
translate2 : 2.427158243022859
replace   : 4.579746678471565
krinker
quelle
4
>>> s = "string. With. Punctuation?"
>>> s = re.sub(r'[^\w\s]','',s)
>>> re.split(r'\s*', s)


['string', 'With', 'Punctuation']
Pablo Rodriguez Bertorello
quelle
2
Bitte bearbeiten Sie mit weiteren Informationen. Nur-Code- und "Versuch dies" -Antworten werden nicht empfohlen, da sie keinen durchsuchbaren Inhalt enthalten und nicht erklären, warum jemand "dies versuchen" sollte.
Paritosh
4

Hier ist eine Lösung ohne 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
  • Ersetzt die Interpunktionen durch Leerzeichen
  • Ersetzen Sie mehrere Leerzeichen zwischen Wörtern durch ein einzelnes Leerzeichen
  • Entfernen Sie ggf. die nachfolgenden Leerzeichen mit strip ()
ngub05
quelle
4

Ein Einzeiler kann in nicht sehr strengen Fällen hilfreich sein:

''.join([c for c in s if c.isalnum() or c.isspace()])
Dom Gray
quelle
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
Animeartistfromhell7
quelle
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 ("____________")
Isayas Wakgari Kelbessa
quelle
0

Warum benutzt keiner von euch das?

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

Zu langsam?

Dehua Li
quelle
Beachten Sie, dass dadurch auch Leerzeichen entfernt werden.
Georgy
0

Berücksichtigung von Unicode. Code in Python3 überprüft.

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

Entfernen Sie mit Python Stoppwörter aus der Textdatei

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')
Isayas Wakgari Kelbessa
quelle
-2

Ich benutze gerne eine Funktion wie diese:

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
Disk Giant
quelle
1
Dies entfernt Zeichen von Anfang und Ende; Verwenden Sie abc.strip(string.punctuation)stattdessen dafür. Solche Zeichen in der Mitte werden nicht entfernt .
Martijn Pieters