Cara terbaik untuk menghilangkan tanda baca dari string

638

Sepertinya harus ada cara yang lebih sederhana daripada:

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

Disana?

Lawrence Johnston
sumber
3
Tampak jelas bagi saya. Mengapa Anda ingin mengubahnya? Jika Anda ingin lebih mudah, hanya membungkus apa yang baru saja Anda tulis dalam suatu fungsi.
Hannes Ovrén
2
Yah, sepertinya agak seperti menggunakan efek samping dari str.translate untuk melakukan pekerjaan itu. Saya berpikir mungkin ada sesuatu yang lebih seperti str.strip (karakter) yang bekerja pada seluruh string, bukan hanya batas yang telah saya lewatkan.
Lawrence Johnston
2
Tergantung pada data juga. Menggunakan ini pada data di mana ada nama server dengan garis bawah sebagai bagian dari nama (beberapa tempat umum) dapat menjadi buruk. Pastikan Anda tahu data dan apa yang terkandung di dalamnya atau Anda bisa berakhir dengan subset dari masalah clbuttic.
EBGreen
54
Tergantung juga pada apa yang Anda sebut tanda baca. " The temperature in the O'Reilly & Arbuthnot-Smythe server's main rack is 40.5 degrees." berisi persis SATU karakter tanda baca, yang kedua "."
John Machin
37
Saya terkejut tidak ada yang menyebutkan bahwa string.punctuationtidak termasuk tanda baca non-Inggris sama sekali. Saya sedang berpikir tentang。 ,!? : × “” 〟, dan sebagainya.
Clément

Jawaban:

929

Dari perspektif efisiensi, Anda tidak akan terkalahkan

s.translate(None, string.punctuation)

Untuk versi Python yang lebih tinggi gunakan kode berikut:

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

Itu melakukan operasi string mentah di C dengan tabel pencarian - tidak banyak yang akan mengalahkan itu tetapi menulis kode C Anda sendiri.

Jika kecepatan bukan masalah, opsi lain adalah:

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

Ini lebih cepat daripada s.replace dengan masing-masing char, tetapi tidak akan berkinerja sebaik pendekatan python non-murni seperti regex atau string.translate, seperti yang Anda lihat dari timing di bawah ini. Untuk jenis masalah ini, melakukannya di level serendah mungkin terbayar.

Kode waktu:

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)

Ini memberikan hasil sebagai berikut:

sets      : 19.8566138744
regex     : 6.86155414581
translate : 2.12455511093
replace   : 28.4436721802
Brian
sumber
27
Terima kasih atas info waktunya, saya berpikir untuk melakukan sesuatu seperti itu sendiri, tetapi tulisan Anda lebih baik daripada apa pun yang akan saya lakukan dan sekarang saya dapat menggunakannya sebagai templat untuk kode waktu mendatang yang ingin saya tulis :).
Lawrence Johnston
29
Jawaban yang bagus Anda dapat menyederhanakannya dengan menghapus tabel. Dokumen mengatakan: "setel argumen tabel ke Tidak Ada untuk terjemahan yang hanya menghapus karakter" ( docs.python.org/library/stdtypes.html#str.translate )
Alexandros Marinos
3
Perlu dicatat juga bahwa menerjemahkan () berperilaku berbeda untuk objek str dan unicode, jadi Anda harus yakin bahwa Anda selalu bekerja dengan tipe data yang sama, tetapi pendekatan dalam jawaban ini bekerja dengan baik untuk keduanya, yang berguna.
Richard J
36
Dalam Python3, table = string.maketrans("","")harus diganti dengan table = str.maketrans({key: None for key in string.punctuation})?
SparkAndShine
19
Untuk memperbarui diskusi, pada Python 3.6, regexsekarang adalah metode yang paling efisien! Ini hampir 2x lebih cepat daripada menerjemahkan. Juga, set dan ganti tidak lagi begitu buruk! Keduanya ditingkatkan lebih dari faktor 4 :)
Ryan Soklaski
143

Ekspresi reguler cukup sederhana, jika Anda mengetahuinya.

import re
s = "string. With. Punctuation?"
s = re.sub(r'[^\w\s]','',s)
Eratosthenes
sumber
4
@Outlier Explanation: menggantikan bukan (^) karakter atau spasi kata dengan string kosong. Namun berhati-hatilah, \ w cocok dengan garis bawah biasanya.
Matthias
4
@ SIslam Saya pikir ini akan bekerja dengan unicode dengan set unicode flag, yaitu s = re.sub(r'[^\w\s]','',s, re.UNICODE). Mengujinya dengan python 3 di linux ia bekerja bahkan tanpa bendera menggunakan huruf tamil, தமிழ்.
Matthias
@ Matthias Saya mencoba kode dengan Python 3.6.5 pada Mac, keluaran huruf Tamil terlihat sedikit berbeda, input தமிழ் menjadi தமழ. Saya tidak memiliki pengetahuan tentang Tamil, tidak yakin apakah itu yang diharapkan.
Shiouming
71

Untuk kenyamanan penggunaan, saya meringkas catatan tanda baca striping dari string di kedua Python 2 dan Python 3. Silakan merujuk ke jawaban lain untuk deskripsi rinci.


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
sumber
51
myString.translate(None, string.punctuation)
pyrou
sumber
4
ah, saya mencoba ini tetapi tidak berhasil dalam semua kasus. myString.translate (string.maketrans ("", ""), string.punctuation) berfungsi dengan baik.
Aidan Kane
12
Perhatikan bahwa untuk strPython 3, dan unicodePython 2, deletecharsargumennya tidak didukung.
agf
4
myString.translate (string.maketrans ("", ""), string.punctuation) TIDAK akan bekerja dengan string unicode (ditemukan dengan cara yang sulit)
Marc Maxmeister
44
TypeError: translate() takes exactly one argument (2 given):(
Brian Tingle
3
@BrianTingle: lihat kode Python 3 di komentar saya (melewati satu argumen). Ikuti tautannya, untuk melihat kode Python 2 yang berfungsi dengan unicode dan adaptasi Python 3
jfs
29

Saya biasanya menggunakan sesuatu seperti ini:

>>> s = "string. With. Punctuation?" # Sample string
>>> import string
>>> for c in string.punctuation:
...     s= s.replace(c,"")
...
>>> s
'string With Punctuation'
S.Lott
sumber
2
Sebuah uglified satu-liner: reduce(lambda s,c: s.replace(c, ''), string.punctuation, s).
jfs
1
hebat, namun tidak menghilangkan beberapa fluktuasi seperti tanda hubung yang lebih panjang
Vladimir Stazhilov
25

string.punctuationhanya ASCII ! Cara yang lebih benar (tetapi juga jauh lebih lambat) adalah dengan menggunakan modul 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

Anda dapat menggeneralisasi dan menghapus jenis karakter lain juga:

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

Ini juga akan menghapus karakter seperti ~*+§$yang mungkin atau tidak mungkin "tanda baca" tergantung pada sudut pandang seseorang.

Björn Lindqvist
sumber
Sayangnya, hal-hal seperti ~ini bukan bagian dari kategori tanda baca. Anda juga perlu menguji untuk kategori Simbol.
CJ Jackson
24

Belum tentu lebih sederhana, tetapi dengan cara yang berbeda, jika Anda lebih akrab dengan keluarga kembali.

import re, string
s = "string. With. Punctuation?" # Sample string 
out = re.sub('[%s]' % re.escape(string.punctuation), '', s)
Vinko Vrsalovic
sumber
1
Berfungsi karena string.punctuation memiliki urutan, -. dalam urutan ASCII yang tepat, naik, tanpa celah. Meskipun Python memiliki hak ini, ketika Anda mencoba menggunakan subset dari string.punctuation, itu bisa menjadi penghenti karena kejutan "-".
S.Lott
2
Sebenarnya, ini masih salah. Urutan "\]" diperlakukan sebagai pelarian (kebetulan tidak menutup] sehingga melewati kegagalan lain), tetapi membiarkan \ tidak terhindar. Anda harus menggunakan re.escape (string.punctuation) untuk mencegah hal ini.
Brian
1
Ya, saya menghapusnya karena itu berfungsi sebagai contoh untuk menjaga hal-hal sederhana, tetapi Anda benar bahwa itu harus dimasukkan.
Vinko Vrsalovic
13

Untuk nilai Python 3 stratau Python 2 unicode, str.translate()hanya dibutuhkan kamus; codepoints (bilangan bulat) dilihat dalam pemetaan itu dan apa pun yang dipetakan untuk Nonedihapus.

Untuk menghapus tanda baca (beberapa?), Gunakan:

import string

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

The dict.fromkeys()metode kelas membuatnya sepele untuk membuat pemetaan, pengaturan semua nilai untuk Noneberdasarkan urutan kunci.

Untuk menghapus semua tanda baca, tidak hanya tanda baca ASCII, tabel Anda harus sedikit lebih besar; lihat jawaban JF Sebastian (versi 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'))
Martijn Pieters
sumber
Untuk mendukung Unicode, string.punctuationtidak cukup. Lihat jawaban saya
jfs
@ JSFSebastian: memang, jawaban saya hanya menggunakan karakter yang sama dengan yang terpilih. Menambahkan versi Python 3 dari tabel Anda.
Martijn Pieters
jawaban terpilih hanya berfungsi untuk string ascii. Jawaban Anda mengklaim secara eksplisit dukungan Unicode.
jfs
1
@ JSFSebastian: ini berfungsi untuk string Unicode. Itu strip tanda baca ASCII. Saya tidak pernah mengklaim itu menghapus semua tanda baca. :-) Intinya adalah untuk memberikan teknik yang benar untuk unicodeobjek vs objek Python 2 str.
Martijn Pieters
12

string.punctuationmerindukan banyak tanda baca yang biasa digunakan di dunia nyata. Bagaimana dengan solusi yang berfungsi untuk tanda baca 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()

Secara pribadi, saya percaya ini adalah cara terbaik untuk menghapus tanda baca dari string dengan Python karena:

  • Ini menghapus semua tanda baca Unicode
  • Mudah dimodifikasi, misalnya Anda dapat \{S}menghapus tanda baca jika Anda ingin menghapusnya, tetapi pertahankan simbol seperti $.
  • Anda dapat benar-benar spesifik tentang apa yang ingin Anda simpan dan apa yang ingin Anda hapus, misalnya \{Pd}hanya akan menghapus tanda hubung.
  • Regex ini juga menormalkan spasi putih. Ini memetakan tab, carriage return, dan keanehan lainnya ke ruang tunggal yang bagus.

Ini menggunakan properti karakter Unicode, yang bisa Anda baca lebih lanjut di Wikipedia .

Zach
sumber
9

Saya belum melihat jawaban ini. Cukup gunakan regex; itu menghapus semua karakter selain karakter kata ( \w) dan karakter angka ( \d), diikuti oleh karakter spasi putih ( \s):

import re
s = "string. With. Punctuation?" # Sample string 
out = re.sub(ur'[^\w\d\s]+', '', s)
Blairg23
sumber
1
\dredundan karena merupakan subset dari \w.
Blhsing
Karakter angka dianggap sebagai bagian dari karakter Word? Saya pikir karakter Word adalah karakter apa saja yang dapat membangun kata nyata, misalnya a-zA-Z?
Blairg23
Ya, "kata" di regex termasuk huruf, angka, dan garis bawah. Silakan lihat deskripsi \wdalam dokumentasi: docs.python.org/3/library/re.html
blhsing
8

Berikut ini adalah satu-liner untuk 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
sumber
7

Ini mungkin bukan solusi terbaik namun ini adalah bagaimana saya melakukannya.

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

Berikut adalah fungsi yang saya tulis. Ini tidak terlalu efisien, tetapi sederhana dan Anda dapat menambah atau menghapus tanda baca yang Anda inginkan:

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.Tautology
sumber
5
import re
s = "string. With. Punctuation?" # Sample string 
out = re.sub(r'[^a-zA-Z0-9\s]', '', s)
Haythem HADHAB
sumber
Sepertinya itu hanya akan berfungsi untuk karakter ASCII.
avirr
5

Sama seperti pembaruan, saya menulis ulang contoh @Brian di Python 3 dan membuat perubahan untuk memindahkan langkah kompilasi regex di dalam fungsi. Pikiranku di sini adalah mengatur waktu setiap langkah yang diperlukan untuk membuat fungsi berfungsi. Mungkin Anda menggunakan komputasi terdistribusi dan tidak dapat memiliki objek regex dibagi antara pekerja Anda dan perlu memiliki re.compilelangkah pada setiap pekerja. Juga, saya ingin tahu waktu dua implementasi maketrans yang berbeda untuk Python 3

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

vs.

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

Plus saya menambahkan metode lain untuk menggunakan set, di mana saya memanfaatkan fungsi persimpangan untuk mengurangi jumlah iterasi.

Ini adalah kode lengkap:

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

Ini hasil saya:

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


['string', 'With', 'Punctuation']
Pablo Rodriguez Bertorello
sumber
2
Harap edit dengan informasi lebih lanjut. Jawaban khusus kode dan "coba ini" tidak disarankan, karena tidak mengandung konten yang dapat ditelusuri, dan jangan jelaskan mengapa seseorang harus "coba ini".
Paritosh
4

Inilah solusi tanpa 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
  • Mengganti tanda baca dengan spasi
  • Ganti beberapa spasi di antara kata dengan satu spasi
  • Hapus spasi tambahan, jika ada dengan strip ()
ngub05
sumber
4

Satu kalimat bisa membantu dalam kasus yang tidak terlalu ketat:

''.join([c for c in s if c.isalnum() or c.isspace()])
Dom Grey
sumber
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
sumber
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
sumber
0

Kenapa tidak ada yang menggunakan ini?

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

Terlalu lambat?

Dehua Li
sumber
Perhatikan bahwa ini juga akan menghapus spasi.
Georgy
0

Mempertimbangkan unicode. Kode diperiksa dalam 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'))
Rajan saha Raju
sumber
-1

Hapus kata-kata berhenti dari file teks menggunakan 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')
Isayas Wakgari Kelbessa
sumber
-2

Saya suka menggunakan fungsi seperti ini:

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 Raksasa
sumber
1
Ini adalah pengupasan karakter dari awal dan akhir; gunakan abc.strip(string.punctuation)untuk itu. Itu tidak akan menghapus karakter seperti di tengah .
Martijn Pieters