Cách tốt nhất để loại bỏ dấu câu từ một chuỗi


638

Có vẻ như nên có một cách đơn giản hơn:

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

Lanhung?


3
Có vẻ khá đơn giản với tôi. Tại sao bạn muốn thay đổi nó? Nếu bạn muốn nó dễ dàng hơn chỉ cần bọc những gì bạn vừa viết trong một hàm.
Hannes Ovrén

2
Chà, có vẻ như một loại tin tặc đã được sử dụng một loại tác dụng phụ của str.translate để thực hiện công việc. Tôi đã nghĩ rằng có thể có một cái gì đó giống như str.strip (ký tự) hoạt động trên toàn bộ chuỗi thay vì chỉ các ranh giới mà tôi đã bỏ lỡ.
Lawrence Johnston

2
Phụ thuộc vào dữ liệu quá. Sử dụng điều này trên dữ liệu có tên máy chủ có dấu gạch dưới là một phần của tên (một số vị trí khá phổ biến) có thể là xấu. Chỉ cần chắc chắn rằng bạn biết dữ liệu và những gì nó liên quan hoặc bạn có thể kết thúc với một tập hợp con của vấn đề clbuttic.
EBGreen

54
Cũng phụ thuộc vào những gì bạn gọi là dấu chấm câu. " The temperature in the O'Reilly & Arbuthnot-Smythe server's main rack is 40.5 degrees." chứa chính xác MỘT ký tự dấu chấm câu, ký tự thứ hai "."
John Machin

37
Tôi ngạc nhiên không ai đề cập rằng string.punctuationkhông bao gồm dấu câu không phải tiếng Anh. Tôi đang suy nghĩ về。 ,? × × hung ”, v.v.
Clément

Câu trả lời:


929

Từ góc độ hiệu quả, bạn sẽ không đánh bại

s.translate(None, string.punctuation)

Đối với các phiên bản cao hơn của Python, sử dụng mã sau:

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

Đó là thực hiện các hoạt động chuỗi thô trong C bằng bảng tra cứu - không có nhiều thứ sẽ đánh bại điều đó ngoài việc viết mã C của riêng bạn.

Nếu tốc độ không phải là một mối lo, thì một lựa chọn khác là:

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

Tốc độ này nhanh hơn s.replace với mỗi char, nhưng sẽ không thực hiện cũng như các cách tiếp cận python không thuần túy như regexes hoặc string.translate, như bạn có thể thấy trong các khoảng thời gian dưới đây. Đối với loại vấn đề này, làm nó ở mức độ thấp nhất có thể sẽ được đền đáp.

Mã thời gian:

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)

Điều này cho kết quả như sau:

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

27
Cảm ơn thông tin về thời gian, tôi đã suy nghĩ về việc tự mình làm một cái gì đó, nhưng bạn viết tốt hơn bất cứ điều gì tôi đã làm và bây giờ tôi có thể sử dụng nó làm mẫu cho bất kỳ mã thời gian nào trong tương lai tôi muốn viết :).
Lawrence Johnston

29
Câu trả lời chính xác. Bạn có thể đơn giản hóa nó bằng cách loại bỏ bảng. Các tài liệu nói: "đặt đối số bảng thành Không có cho các bản dịch chỉ xóa các ký tự" ( docs.python.org/l Library / stdtypes.html # str.translate )
Alexandros Marinos

3
cũng đáng lưu ý rằng transl () hành xử khác nhau đối với các đối tượng str và unicode, vì vậy bạn cần chắc chắn rằng bạn luôn làm việc với cùng một kiểu dữ liệu, nhưng cách tiếp cận trong câu trả lời này hoạt động tốt như nhau cho cả hai, rất tiện dụng.
Richard J

36
Trong Python3, table = string.maketrans("","")nên được thay thế bằng table = str.maketrans({key: None for key in string.punctuation})?
SparkAndShine

19
Để cập nhật cuộc thảo luận, kể từ Python 3.6, regexgiờ đây là phương pháp hiệu quả nhất! Nó nhanh hơn gần gấp 2 lần so với dịch. Ngoài ra, bộ và thay thế không còn quá tệ! Cả hai đều được cải thiện với hơn 4 nhân tố :)
Ryan Soklaski

143

Biểu thức thông thường là đủ đơn giản, nếu bạn biết chúng.

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

4
@ Giải thích trước: thay thế không (^) ký tự từ hoặc khoảng trắng bằng chuỗi trống. Mặc dù vậy, hãy cẩn thận, ví dụ, \ w khớp với dấu gạch dưới quá thường xuyên.
Matthias

4
@SIslam Tôi nghĩ rằng nó sẽ hoạt động với unicode với bộ cờ unicode, tức là s = re.sub(r'[^\w\s]','',s, re.UNICODE). Thử nghiệm nó với python 3 trên linux, nó hoạt động ngay cả khi không có cờ bằng các chữ cái tamil,.
Matthias

@Matthias Tôi đã thử mã với Python 3.6.5 trên Mac, đầu ra các chữ cái Tamil trông hơi khác một chút, đầu vào தமிழ் trở thành. Tôi không có kiến ​​thức về tiếng Tamil, không chắc là điều đó có được mong đợi không.
shiouming

71

Để thuận tiện cho việc sử dụng, tôi tổng hợp lưu ý về việc ngắt dấu chấm câu từ một chuỗi trong cả Python 2 và Python 3. Vui lòng tham khảo các câu trả lời khác để biết mô tả chi tiết.


Con trăn 2

import string

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

Con trăn 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, tôi đã thử nó nhưng nó không hoạt động trong mọi trường hợp. myString.translate (string.maketrans ("", ""), string.puncinating) hoạt động tốt.
Aidan Kane

12
Lưu ý rằng đối với strPython 3 và unicodetrong Python 2, deletecharsđối số không được hỗ trợ.
agf

4
myString.translate (string.maketrans ("", ""), string.puncinating) sẽ KHÔNG hoạt động với các chuỗi unicode (tìm ra cách khó khăn)
Marc Maxmeister

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

3
@BrianTingle: nhìn vào mã Python 3 trong bình luận của tôi (nó vượt qua một đối số). Theo liên kết, để xem mã Python 2 hoạt động với unicode và điều chỉnh Python 3 của nó
jfs

29

Tôi thường sử dụng một cái gì đó như thế này:

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

2
Một lót xấu xí : reduce(lambda s,c: s.replace(c, ''), string.punctuation, s).
JFS

1
tuyệt vời, tuy nhiên không loại bỏ một số tính toán như dấu gạch nối dài hơn
Vladimir Stazhilov

25

string.punctuationlà ASCII chỉ ! Một cách chính xác hơn (nhưng cũng chậm hơn nhiều) là sử dụng mô-đun unicodingata:

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

Bạn cũng có thể khái quát hóa và loại bỏ các loại ký tự khác:

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

Nó cũng sẽ loại bỏ các ký tự như ~*+§$có thể có hoặc không có "dấu chấm câu" tùy theo quan điểm của một người.



Thật không may, những thứ như ~không phải là một phần của thể loại dấu câu. Bạn cũng cần phải kiểm tra cho danh mục Biểu tượng là tốt.
CJ Jackson

24

Không nhất thiết phải đơn giản, nhưng một cách khác, nếu bạn quen thuộc hơn với gia đình re.

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

1
Hoạt động vì chuỗi. Dấu chấm câu có trình tự, -. theo đúng thứ tự, tăng dần, không có khoảng trống, thứ tự ASCII. Mặc dù Python có quyền này, nhưng khi bạn cố gắng sử dụng tập hợp con của chuỗi. Dấu chấm câu, nó có thể là một trình chặn hiển thị vì sự bất ngờ "-".
S.Lott

2
Thật ra, nó vẫn sai. Chuỗi "\]" được coi là một lối thoát (ngẫu nhiên không đóng] để bỏ qua một thất bại khác), nhưng để lại \ không thoát khỏi. Bạn nên sử dụng re.escape (chuỗi. Dấu chấm câu) để ngăn chặn điều này.
Brian

1
Vâng, tôi đã bỏ qua nó vì nó làm việc cho ví dụ đơn giản, nhưng bạn nói đúng rằng nó nên được kết hợp.
Vinko Vrsalovic

13

Đối với các giá trị Python 3 strhoặc Python 2 unicode, str.translate()chỉ mất một từ điển; các điểm mã (số nguyên) được tra cứu trong ánh xạ đó và mọi thứ được ánh xạ tới Nonesẽ bị xóa.

Để xóa dấu chấm (một số?) Sau đó, sử dụng:

import string

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

Các dict.fromkeys()phương pháp lớp học làm cho nó tầm thường để tạo ra các bản đồ, thiết lập tất cả các giá trị Nonedựa trên chuỗi các phím.

Để xóa tất cả dấu chấm câu, không chỉ dấu chấm câu ASCII, bảng của bạn cần lớn hơn một chút; xem câu trả lời của JF Sebastian (phiên bả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'))

Để hỗ trợ Unicode, string.punctuationlà không đủ. Xem câu trả lời của tôi
jfs

@JFSebastian: thực sự, câu trả lời của tôi chỉ là sử dụng các ký tự giống như nhân vật được bình chọn hàng đầu. Đã thêm phiên bản Python 3 của bảng của bạn.
Martijn Pieters

câu trả lời được bình chọn hàng đầu chỉ hoạt động cho chuỗi ascii. Câu trả lời của bạn yêu cầu rõ ràng hỗ trợ Unicode.
JFS

1
@JFSebastian: nó hoạt động cho các chuỗi Unicode. Nó dải chấm câu ASCII. Tôi không bao giờ tuyên bố nó dải tất cả các dấu chấm câu. :-) Vấn đề là cung cấp kỹ thuật chính xác cho unicodecác đối tượng so với các đối tượng Python 2 str.
Martijn Pieters

12

string.punctuationbỏ lỡ vô số dấu chấm câu thường được sử dụng trong thế giới thực. Làm thế nào về một giải pháp hoạt động cho dấu câu không 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()

Cá nhân, tôi tin rằng đây là cách tốt nhất để xóa dấu câu khỏi chuỗi trong Python vì:

  • Nó loại bỏ tất cả các dấu chấm câu Unicode
  • Nó có thể dễ dàng sửa đổi, ví dụ: bạn có thể xóa \{S}nếu bạn muốn xóa dấu chấm câu, nhưng giữ các ký hiệu như $.
  • Bạn có thể thực sự cụ thể về những gì bạn muốn giữ và những gì bạn muốn xóa, ví dụ như \{Pd}sẽ chỉ xóa dấu gạch ngang.
  • Regex này cũng bình thường hóa khoảng trắng. Nó ánh xạ các tab, vận chuyển trở lại, và những điều kỳ lạ khác đến những không gian đơn, đẹp.

Điều này sử dụng các thuộc tính ký tự Unicode, mà bạn có thể đọc thêm về Wikipedia .


9

Tôi chưa thấy câu trả lời này. Chỉ cần sử dụng một regex; nó loại bỏ tất cả các ký tự bên cạnh các ký tự từ ( \w) và ký tự số ( \d), theo sau là ký tự khoảng trắng ( \s):

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

1
\dlà dư thừa vì nó là một tập hợp con của \w.
blhsing

Số ký tự được coi là tập hợp con của các ký tự Word? Tôi nghĩ rằng một nhân vật Word là bất kỳ nhân vật nào có thể tạo ra một từ thực sự, ví dụ a-zA-Z?
Blairg23

Có, một "từ" trong regex bao gồm bảng chữ cái, số và dấu gạch dưới. Xin xem mô tả cho \wtrong tài liệu: docs.python.org/3/library/re.html
blhsing

8

Đây là một lớp lót cho 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

Đây có thể không phải là giải pháp tốt nhất tuy nhiên đây là cách tôi đã làm.

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

6

Đây là một chức năng tôi đã viết. Nó không hiệu quả lắm, nhưng nó đơn giản và bạn có thể thêm hoặc xóa bất kỳ dấu câu nào bạn muốn:

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)

Có vẻ như điều đó sẽ chỉ làm việc cho các ký tự ASCII.
avirr

5

Cũng giống như một bản cập nhật, tôi viết lại ví dụ @Brian trong Python 3 và thực hiện các thay đổi cho nó để di chuyển bước biên dịch regex bên trong hàm. Tôi nghĩ ở đây là thời gian từng bước cần thiết để làm cho chức năng hoạt động. Có lẽ bạn đang sử dụng điện toán phân tán và không thể có đối tượng regex được chia sẻ giữa các công nhân của bạn và cần phải có re.compiletừng bước tại mỗi công nhân. Ngoài ra, tôi đã tò mò về thời gian hai triển khai maketrans khác nhau cho Python 3

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

đấu với

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

Thêm vào đó tôi đã thêm một phương thức khác để sử dụng tập hợp, trong đó tôi tận dụng hàm giao nhau để giảm số lần lặp.

Đây là mã hoàn chỉnh:

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

Đây là kết quả của tôi:

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
Vui lòng chỉnh sửa với nhiều thông tin hơn. Các câu trả lời chỉ dành cho mã và "thử cái này" không được khuyến khích, vì chúng không chứa nội dung có thể tìm kiếm và không giải thích lý do tại sao ai đó nên "thử cái này".
Paritosh

4

Đây là một giải pháp không có 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
  • Thay thế dấu câu bằng dấu cách
  • Thay thế nhiều khoảng trắng ở giữa các từ bằng một khoảng trắng
  • Xóa các dấu cách, nếu có với dải ()

4

Một lớp lót có thể hữu ích trong các trường hợp không nghiêm ngặt:

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

Tại sao không ai trong số bạn sử dụng điều này?

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

Quá chậm?


Lưu ý rằng điều này cũng sẽ loại bỏ không gian.
Georgy

0

Xem xét unicode. Mã kiểm tra trong 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

Xóa các từ dừng khỏi tệp văn bản bằng 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

Tôi thích sử dụng một chức năng như thế này:

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
Đây là tước nhân vật từ đầu và cuối; sử dụng abc.strip(string.punctuation)thay thế cho điều đó. Nó sẽ không loại bỏ các nhân vật như vậy ở giữa .
Martijn Pieters
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.