Bir dizeden noktalama işaretleri çıkarmanın en iyi yolu


636

Görünüşe göre daha basit bir yol olmalı:

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

Var mı?


3
Bana çok kolay geliyor. Neden değiştirmek istiyorsun? Eğer daha kolay istiyorsanız, sadece bir fonksiyonda yazdıklarınızı sarın.
Hannes Ovrén

2
İşi yapmak için tercüme edilmek gibi bir tür yan etki kullanmak biraz kibirli görünüyordu. Ben sadece kaçırdığım sınırları yerine tüm dize üzerinde çalıştı str.strip (chars) gibi bir şey olabilir düşünüyordum.
Lawrence Johnston

2
Verilere de bağlıdır. Bunu, adın bir parçası olarak alt çizgileri olan sunucu adlarının bulunduğu verilerde kullanmak (bazı yerlerde oldukça yaygın) kötü olabilir. Sadece verileri ve neleri içerdiğini bildiğinizden emin olun, ya da clbuttic sorunun bir alt kümesiyle sonuçlanabilir.
EBGreen

54
Noktalama işareti olarak adlandırdığınız şeye de bağlıdır. " The temperature in the O'Reilly & Arbuthnot-Smythe server's main rack is 40.5 degrees." tam olarak bir noktalama işareti, ikincisini içeriyor "."
John Machin

37
Hiç kimse string.punctuationİngilizce olmayan noktalama işaretleri içermediğini söyledi şaşırdım . Thinking ,!? : × “” 〟hakkında düşünüyorum.
Clément

Yanıtlar:


929

Verimlilik açısından bakıldığında,

s.translate(None, string.punctuation)

Python'un daha yüksek sürümleri için aşağıdaki kodu kullanın:

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

Bir arama tablosu ile C'de ham dize işlemleri gerçekleştiriyor - bunu yenecek çok şey yok ama kendi C kodunuzu yazıyor.

Hız endişe etmiyorsa, başka bir seçenek:

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

Bu, her karakterle s.replace'den daha hızlıdır, ancak aşağıdaki zamanlamalardan görebileceğiniz gibi regexes veya string.translate gibi saf olmayan python yaklaşımları kadar iyi performans göstermez. Bu tür bir sorun için, bunu mümkün olduğunca düşük bir seviyede yapmak işe yarar.

Zamanlama kodu:

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)

Bu, aşağıdaki sonuçları verir:

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

27
Zamanlama bilgisi için teşekkürler, kendim gibi bir şey yapmayı düşünüyordum, ama seninki yaptığım her şeyden daha iyi yazılmış ve şimdi yazmak istediğim herhangi bir zamanlama kodu için bir şablon olarak kullanabilirim :).
Lawrence Johnston

29
Mükemmel cevap. Tabloyu kaldırarak basitleştirebilirsiniz. Dokümanlar şunları söylüyor: "Yalnızca karakterleri silen çeviriler için tablo bağımsız değişkenini Yok olarak ayarlayın" ( docs.python.org/library/stdtypes.html#str.translate )
Alexandros Marinos

3
translate () öğesinin str ve unicode nesneler için farklı davrandığını da belirtmek gerekir, bu nedenle her zaman aynı veri türüyle çalıştığınızdan emin olmanız gerekir, ancak bu yanıttaki yaklaşım her ikisi için de eşit derecede iyi çalışır, bu da kullanışlı.
Richard J

36
Python3, table = string.maketrans("","")ile değiştirilmesi gerekir table = str.maketrans({key: None for key in string.punctuation})?
SparkAndShine

19
Tartışmayı güncellemek için, Python 3.6'dan itibaren, regexşimdi en etkili yöntem! Çeviriden neredeyse 2 kat daha hızlıdır. Ayrıca, setler ve değiştirme artık o kadar da kötü değil! Her ikisi de 4 kat fazla geliştirildi :)
Ryan Soklaski

143

Biliyorsanız düzenli ifadeler yeterince basittir.

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

4
@Outlier Explanation: (^) sözcük karakterlerini veya boşluklarını boş dize ile değiştirir. Ancak dikkatli olun, \ w genellikle alt çizgi ile eşleşir.
Matthias

4
@SIslam Bence unicode bayrak seti ile unicode ile çalışacağını düşünüyorum s = re.sub(r'[^\w\s]','',s, re.UNICODE). Linux üzerinde python 3 ile test edilmesi, tamil harfleri kullanarak bayrağı olmadan bile çalışır, தமிழ்.
Matthias

@Matthias Kodu Mac'te Python 3.6.5 ile denedim, Tamil harf çıktısı biraz farklı görünüyor, giriş தமிழ் தமிழ் oluyor. Tamil hakkında bilgim yok, bunun beklenip beklenmediğinden emin değilim.
19:20

70

Kullanım kolaylığı için, hem Python 2 hem de Python 3'teki bir dizeden şerit noktalama notunu özetliyorum. Ayrıntılı açıklama için lütfen diğer cevaplara bakın.


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)

4
ah, bunu denedim ama her durumda işe yaramıyor. myString.translate (string.maketrans ("", ""), string.punctuation) iyi çalışıyor.
Aidan Kane

12
Söz konusu Not strPython 3'te ve unicodePython 2'de, deletecharsargüman desteklenmez.
agf

4
myString.translate (string.maketrans ("", ""), string.punctuation) unicode dizelerle çalışmaz (zor yoldan
öğrendim

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

3
@BrianTingle: Yorumumdaki Python 3 koduna bakın (bir argümanı geçer). Unicode ve Python 3 uyarlaması
jfs

29

Genellikle böyle bir şey kullanırım:

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

2
Çirkin bir astar reduce(lambda s,c: s.replace(c, ''), string.punctuation, s).
jfs

1
harika, ancak daha uzun tire gibi bazı rahatsızlıkları kaldırmaz
Vladimir Stazhilov

25

string.punctuationASCII olduğunu sadece ! Daha doğru (ama aynı zamanda çok daha yavaş) bir yol, unicodedata modülünü kullanmaktır:

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

Diğer karakter türlerini de genelleştirebilir ve silebilirsiniz:

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

Ayrıca, ~*+§$kişinin bakış açısına bağlı olarak "noktalama işareti" olabilecek veya olmayacak karakterler de çıkarır .


3
Şunları yapabilirsiniz:regex.sub(ur"\p{P}+", "", text)
jfs

Ne yazık ki, gibi şeyler ~noktalama kategorisinin bir parçası değildir. Semboller kategorisini de test etmeniz gerekir.
CJ Jackson

24

Mutlaka daha basit değil, farklı bir yol, eğer re ailesine daha aşina iseniz.

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

1
String.punctuation, - dizisine sahip olduğu için çalışır. uygun, artan, boşluk bırakmayan, ASCII düzeninde. Python bu hakka sahip olsa da, string.punctuation öğesinin bir alt kümesini kullanmaya çalıştığınızda, sürpriz "-" nedeniyle bir show-stopper olabilir.
S.Lott

2
Aslında, hala yanlış. "\]" Dizisi bir kaçış olarak ele alınır (tesadüfen kapatılmadan], bu yüzden başka bir hata atlayarak), \ \ çıkışını bırakır. Bunu önlemek için re.escape (string.punctuation) kullanmalısınız.
Brian

1
Evet, atladım, çünkü işleri basit tutmak için örnek için çalıştı, ancak dahil edilmesi gerektiği konusunda haklısınız.
Vinko Vrsalovic

13

Python 3 strveya Python 2 unicodedeğerleri için str.translate()sadece bir sözlük alır; kod noktaları (tamsayılar) bu eşlemede aranır veNone kaldırılır.

Ardından (bazı?) Noktalama işaretlerini kaldırmak için şunu kullanın:

import string

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

dict.fromkeys()Sınıf yöntemi için tüm değerleri ayarlayarak, eşlemesi oluşturmak için Önemsiz yaparNone tuşların sırasına dayalı.

Yalnızca ASCII noktalama işaretlerini değil tüm noktalama işaretlerini kaldırmak için tablonuzun biraz daha büyük olması gerekir; JF Sebastian'ın cevabına bakınız (Python 3 versiyonu):

import unicodedata
import sys

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

Unicode'u desteklemek için string.punctuationyeterli değildir. Cevabımı
jfs

@JFSebastian: gerçekten, cevabım sadece en çok oy alan karakterle aynıydı. Tablonuzun bir Python 3 sürümü eklendi.
Martijn Pieters

en çok oy alan cevap sadece ascii dizeleri için geçerlidir. Yanıtınız açıkça Unicode desteği olduğunu iddia ediyor.
jfs

1
@JFSebastian: Unicode dizeleri için çalışır. ASCII noktalama işaretlerini kaldırır. Asla tüm noktalama işaretlerini kaldırdığını iddia etmedim . :-) Mesele, unicodePython 2 strnesneleri ve nesneler için doğru tekniği sağlamaktı .
Martijn Pieters

12

string.punctuationgerçek dünyada yaygın olarak kullanılan çok sayıda noktalama işaretini kaçırır. ASCII olmayan noktalama işaretleri için çalışan bir çözüme ne dersiniz?

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

Şahsen, bu Python bir dize noktalama işaretleri kaldırmak için en iyi yolu olduğuna inanıyorum:

  • Tüm Unicode noktalama işaretlerini kaldırır
  • Kolayca değiştirilebilir, örneğin \{S}noktalama işaretlerini kaldırmak istiyorsanız kaldırabilirsiniz, ancak$ .
  • Neleri saklamak istediğiniz ve neyi kaldırmak istediğiniz konusunda gerçekten ayrıntılı bilgi edinebilirsiniz. \{Pd} yalnızca tire işaretleri kaldırılır.
  • Bu normal ifade boşlukları da normalleştirir. Sekmeleri, satır başlarını ve diğer tuhaflıkları güzel, tek boşluklarla eşler.

Bu , Wikipedia'da hakkında daha fazla bilgi edinebileceğiniz Unicode karakter özelliklerini kullanır .


9

Bu cevabı henüz görmedim. Sadece normal ifadeyi kullanın; kelime karakterleri ( \w) ve sayı karakterleri ( \d), ardından boşluk karakteri ( \s) dışındaki tüm karakterleri kaldırır :

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

1
\dbir alt kümesi olduğu için gereksizdir \w.
19'da

Sayı karakterleri Word karakterlerinin bir alt kümesi olarak kabul edilir? Bir Word karakterinin, örneğin a-zA-Z?
Blairg23

Evet, normal ifadedeki bir "kelime" alfabe, sayı ve alt çizgi içerir. Lütfen \wbelgelerdeki açıklamaya bakın : docs.python.org/3/library/re.html
blhsing

8

İşte Python 3.5 için bir astar:

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

Bu en iyi çözüm olmayabilir, ancak ben böyle yaptım.

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

6

İşte yazdığım bir fonksiyon. Çok verimli değil, ancak basit ve istediğiniz herhangi bir noktalama işaretini ekleyebilir veya kaldırabilirsiniz:

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)

Bunun sadece ASCII karakterleri için geçerli olduğu anlaşılıyor.
avirr

5

Bir güncelleme olarak, Python 3'te @Brian örneğini yeniden yazdım ve regex derleme adımını işlevin içine taşımak için değişiklikler yaptım. Buradaki düşüncem, işlevin çalışması için gereken her adımı zamanlamaktı. Belki de dağıtılmış bilgi işlem kullanıyorsunuz ve çalışanlarınız arasında regex nesnesi paylaşılamıyor ve re.compileher çalışanda adım atmanız gerekiyor . Ayrıca, Python 3 için iki farklı maketrans uygulamasının zamanını merak ettim

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

vs

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

Ayrıca yineleme sayısını azaltmak için kavşak fonksiyonundan faydalandığım seti kullanmak için başka bir yöntem ekledim.

Bu tam kod:

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

Bu benim sonuçlarım:

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
Lütfen daha fazla bilgi ile düzenleyin. Yalnızca kod ve "bunu dene" yanıtları önerilmez çünkü bunlar aranabilir içerik içermez ve birisinin neden "bunu denemesi" gerektiğini açıklamaz.
Paritosh

4

Regex içermeyen bir çözüm.

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
  • Noktalama işaretlerini boşluklarla değiştirir
  • Sözcükler arasındaki birden çok boşluğu tek bir boşlukla değiştirme
  • Varsa şerit () ile sondaki boşlukları kaldırın

4

Çok katı olmayan durumlarda tek astar yardımcı olabilir:

''.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

Neden hiçbiriniz bunu kullanmıyorsunuz?

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

Çok yavaş?


Bunun boşlukları da kaldıracağını unutmayın.
Georgy

0

Unicode göz önüne alındığında. Python3'te kod kontrol edildi.

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

Dur sözcükleri Python kullanarak metin dosyasından kaldırma

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

Bunun gibi bir işlev kullanmayı seviyorum:

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
Bu, karakterleri başlangıçtan ve sondan çıkarmaktır; abc.strip(string.punctuation)bunun için kullanın . Böyle karakterleri kaldırmaz ortada .
Martijn Pieters
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.