Python, xóa tất cả các ký tự không phải bảng chữ cái khỏi chuỗi


90

Tôi đang viết một chương trình đếm từ bằng Python MapReduce. Vấn đề là có nhiều ký tự không phải bảng chữ cái nằm rải rác trong dữ liệu, tôi đã tìm thấy bài đăng này Tách mọi thứ trừ các ký tự chữ và số khỏi một chuỗi trong Python cho thấy một giải pháp hay bằng cách sử dụng regex, nhưng tôi không chắc chắn cách triển khai nó

def mapfn(k, v):
    print v
    import re, string 
    pattern = re.compile('[\W_]+')
    v = pattern.match(v)
    print v
    for w in v.split():
        yield w, 1

Tôi e rằng tôi không chắc chắn về cách sử dụng thư viện rehoặc thậm chí regex cho vấn đề đó. Tôi không chắc chắn cách áp dụng mẫu regex cho chuỗi đến (dòng sách) vđúng cách để truy xuất dòng mới mà không có bất kỳ ký tự không phải chữ và số nào.

Gợi ý?


vlà toàn bộ một dòng của một cuốn sách (cụ thể là moby dick), tôi đang nói từng từ một chứ không phải char bởi char. Vì vậy, một số từ có thể có dấu "," ở cuối để "indignity" không liên kết với "indignity".
KDecker


Lolx - bạn có nhận được bài tập về nhà trước khi phỏng vấn giống tôi không? Tìm 50 từ được sử dụng nhiều nhất trong Moby Dick và báo cáo tần suất của chúng. Tôi đã làm điều đó trong C ++, IIRC
Mawg cho biết hãy khôi phục Monica vào

1
@Mawg Đó là một bài tập trong lớp "Điện toán đám mây" chưa tốt nghiệp của tôi.
KDecker

Câu trả lời:


128

Sử dụng re.sub

import re

regex = re.compile('[^a-zA-Z]')
#First parameter is the replacement, second parameter is your input string
regex.sub('', 'ab3d*E')
#Out: 'abdE'

Ngoài ra, nếu bạn chỉ muốn xóa một số ký tự nhất định (vì dấu nháy đơn có thể ổn trong đầu vào của bạn ...)

regex = re.compile('[,\.!?]') #etc.

Hmm, tôi hoàn toàn có thể theo dõi nó, nhưng còn mẫu để xóa tất cả các chữ số không phải chữ và số, loại trừ dấu cách thì sao?
KDecker

1
Chỉ cần thêm một khoảng trống vào lớp bộ sưu tập của bạn. tức là ^a-zA-Z thay vì chỉ^a-zA-Z
limasxgoesto0

Trừ khi bạn cũng lo lắng về các dòng mới, trong trường hợp đó a-zA-Z \n. Tôi đang cố gắng tìm một regex có thể gộp cả hai thành một nhưng sử dụng \whoặc \Wkhông mang lại cho tôi hành vi mong muốn. Bạn có thể chỉ cần thêm \nnếu đó là trường hợp.
limasxgoesto0

Ahh, ký tự dòng mới. Đó là vấn đề của tôi nằm ở đâu, tôi đã so sánh kết quả của mình với kết quả đã cho và tôi vẫn chưa hoàn thành. Tôi nghĩ đó là vấn đề của tôi! Cảm ơn // Hmm, tôi đã thử nó với kết quả tương tự char newline, tôi nghĩ còn thiếu một cái nữa .. // Duhhh ... Chữ hoa và chữ thường ... // Cảm ơn mọi sự giúp đỡ, hiện tại hoạt động hoàn hảo!
KDecker

48

Nếu bạn không muốn sử dụng regex, bạn có thể thử

''.join([i for i in s if i.isalpha()])

làm thế nào để tôi tham gia này? với '' .join? in s được chỉ một đối tượng lọc
PirateApp

Chà, đây là những gì tôi đang tìm kiếm. Điều này tính đến kanji, hiragana, katakana, v.v. kudos
root163

34

Bạn có thể sử dụng hàm re.sub () để xóa các ký tự sau:

>>> import re
>>> re.sub("[^a-zA-Z]+", "", "ABC12abc345def")
'ABCabcdef'

re.sub (MẪU TRẬN ĐẤU, THAY THẾ STRING, STRING ĐỂ TÌM KIẾM)

  • "[^a-zA-Z]+" - tìm bất kỳ nhóm ký tự nào KHÔNG phải là a-zA-z.
  • "" - Thay thế các ký tự phù hợp bằng ""

Lưu ý rằng thao tác này cũng sẽ xóa các chữ cái có dấu: ãâàáéèçõ, v.v.
Brad Ahrens

19

Thử:

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

Thao tác này sẽ lấy mọi ký tự từ chuỗi, chỉ giữ lại các ký tự chữ và số và xây dựng lại một chuỗi từ chúng.


1
Câu trả lời này có thể sử dụng nhiều giải thích hơn và liên kết đến tài liệu liên quan.
pdoherty926

4

Phương pháp nhanh nhất là regex

#Try with regex first
t0 = timeit.timeit("""
s = r2.sub('', st)

""", setup = """
import re
r2 = re.compile(r'[^a-zA-Z0-9]', re.MULTILINE)
st = 'abcdefghijklmnopqrstuvwxyz123456789!@#$%^&*()-=_+'
""", number = 1000000)
print(t0)

#Try with join method on filter
t0 = timeit.timeit("""
s = ''.join(filter(str.isalnum, st))

""", setup = """
st = 'abcdefghijklmnopqrstuvwxyz123456789!@#$%^&*()-=_+'
""",
number = 1000000)
print(t0)

#Try with only join
t0 = timeit.timeit("""
s = ''.join(c for c in st if c.isalnum())

""", setup = """
st = 'abcdefghijklmnopqrstuvwxyz123456789!@#$%^&*()-=_+'
""", number = 1000000)
print(t0)


2.6002226710006653 Method 1 Regex
5.739747313000407 Method 2 Filter + Join
6.540099570000166 Method 3 Join

0

Bạn nên sử dụng mô-đun PyPiregex nếu bạn định khớp các lớp thuộc tính Unicode cụ thể. Thư viện này cũng đã được chứng minh là ổn định hơn, đặc biệt là xử lý các văn bản lớn và mang lại kết quả nhất quán trên các phiên bản Python khác nhau. Tất cả những gì bạn cần làm là luôn cập nhật.

Nếu bạn cài đặt nó (sử dụng pip intall regexhoặc pip3 install regex), bạn có thể sử dụng

import regex
print ( regex.sub(r'\P{L}+', '', 'ABCŁąć1-2!Абв3§4“5def”') )
// => ABCŁąćАбвdef

để xóa tất cả các phần gồm 1 hoặc nhiều ký tự không phải là các ký tự Unicode text. Xem bản demo Python trực tuyến . Bạn cũng có thể sử dụng "".join(regex.findall(r'\p{L}+', 'ABCŁąć1-2!Абв3§4“5def”'))để có được kết quả tương tự.

Trong Python re, để khớp với bất kỳ ký tự Unicode nào, người ta có thể sử dụng [^\W\d_]cấu trúc ( Khớp bất kỳ ký tự unicode nào? ).

Vì vậy, để xóa tất cả các ký tự không phải chữ cái, bạn có thể khớp tất cả các chữ cái và nối kết quả:

result = "".join(re.findall(r'[^\W\d_]', text))

Hoặc, xóa tất cả các ký tự khác với những ký tự được so khớp với [^\W\d_]:

result = re.sub(r'([^\W\d_])|.', r'\1', text, re.DOTALL)

Xem bản demo regex trực tuyến . Tuy nhiên , bạn có thể nhận được kết quả không nhất quán trên các phiên bản Python khác nhau vì tiêu chuẩn Unicode đang phát triển và tập hợp các ký tự phù hợp với \wsẽ phụ thuộc vào phiên bản Python. Bạn nên sử dụng regexthư viện PyPi để có được kết quả nhất quán.

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.