Python ลบอักขระที่ไม่ใช่ตัวอักษรทั้งหมดออกจากสตริง


93

ฉันกำลังเขียนโปรแกรม python MapReduce จำนวนคำ ปัญหาคือมีตัวอักษรที่ไม่ใช่ตัวอักษรจำนวนมากเกลื่อนอยู่ในข้อมูลฉันพบว่าโพสต์นี้ลอกทุกอย่างยกเว้นตัวอักษรและตัวเลขจากสตริงใน Pythonซึ่งแสดงวิธีแก้ปัญหาที่ดีโดยใช้ regex แต่ฉันไม่แน่ใจว่าจะใช้งานอย่างไร

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

ฉันเกรงว่าจะไม่แน่ใจว่าจะใช้ไลบรารีreหรือแม้แต่นิพจน์ทั่วไปในเรื่องนั้นได้อย่างไร ฉันไม่แน่ใจว่าจะใช้รูปแบบนิพจน์ทั่วไปกับสตริงขาเข้า (บรรทัดของหนังสือ) อย่างไรvอย่างถูกต้องเพื่อดึงข้อมูลบรรทัดใหม่โดยไม่มีอักขระที่ไม่ใช่ตัวเลขและตัวอักษร

ข้อเสนอแนะ?


vเป็นทั้งบรรทัดของหนังสือ (โดยเฉพาะ moby dick) ฉันจะพูดทีละคำไม่ใช่ char by char ดังนั้นคำบางคำอาจมี "," ต่อท้ายดังนั้น "ความขุ่นเคือง" จึงไม่ตรงกับ "ความขุ่นเคือง"
KDecker


Lolx - คุณได้รับการออกกำลังกายก่อนการสัมภาษณ์ที่บ้านเหมือนกับฉันหรือไม่? ค้นหา 50 คำที่ใช้บ่อยที่สุดใน Moby Dick และรายงานความถี่ ฉันทำใน C ++, IIRC
Mawg บอกว่าคืนสถานะ Monica

1
@Mawg มันเป็นการออกกำลังกายในคลาส "Cloud Computing" ระดับปริญญาตรีของฉัน
KDecker

คำตอบ:


130

ใช้ 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'

หรือหากคุณต้องการลบชุดอักขระบางตัวเท่านั้น (เป็นเครื่องหมายอะพอสทรอฟีในอินพุตของคุณอาจไม่เป็นไร ...

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

อืมฉันสามารถติดตามได้ แต่รูปแบบที่จะลบทั้งหมดที่ไม่ใช่ตัวอักษรและตัวเลขไม่รวมช่องว่าง?
KDecker

1
เพียงเพิ่มพื้นที่ในชั้นเรียนคอลเลกชันของคุณ เช่น^a-zA-Z แทนที่จะเป็นเพียง^a-zA-Z
limasxgoesto0

เว้นแต่คุณจะกังวลเกี่ยวกับการขึ้นใหม่ด้วยในกรณีa-zA-Z \nนี้ ฉันกำลังพยายามหานิพจน์ทั่วไปที่จะรวมทั้งสองอย่างเข้าด้วยกัน แต่ใช้\wหรือ\Wไม่ทำให้ฉันมีพฤติกรรมที่ต้องการ คุณอาจต้องเพิ่ม\nหากเป็นเช่นนั้น
limasxgoesto0

อ่าถ่าน newline นั่นคือปัญหาของฉันฉันกำลังเปรียบเทียบผลลัพธ์ของฉันกับผลลัพธ์ที่ได้รับและฉันก็ยังไม่พอใจ ฉันคิดว่านั่นเป็นปัญหาของฉัน! ขอบคุณ // อืมฉันลองแล้วกับ newline char ผลลัพธ์เดียวกันฉันคิดว่ายังมีอีกอันที่ฉันหายไป .. // Duhhh ... ตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก ... // ขอบคุณสำหรับความช่วยเหลือทั้งหมดทำงานได้อย่างสมบูรณ์ตอนนี้!
KDecker

50

หากคุณไม่ต้องการใช้ regex คุณอาจลองใช้

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

ฉันจะเข้าร่วมได้อย่างไร ด้วย ".join? การพิมพ์จะได้รับเฉพาะวัตถุตัวกรอง
PirateApp

1
ว้าวนี่คือสิ่งที่ฉันกำลังมองหา สิ่งนี้คำนึงถึงคันจิฮิรางานะคาตาคานะ ฯลฯ kudos
root163

34

คุณสามารถใช้ฟังก์ชัน re.sub () เพื่อลบอักขระเหล่านี้:

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

re.sub (รูปแบบการจับคู่, แทนที่ STRING, STRING เพื่อค้นหา)

  • "[^a-zA-Z]+" - มองหากลุ่มอักขระที่ไม่ใช่ a-zA-z
  • "" - แทนที่อักขระที่ตรงกันด้วย ""

โปรดทราบว่าสิ่งนี้จะลบตัวอักษรที่เน้นเสียงเช่นãâàáéèçõเป็นต้น
Brad Ahrens

19

ลอง:

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

สิ่งนี้จะนำทุกตัวอักษรออกจากสตริงโดยเก็บเฉพาะตัวอักษรและตัวเลขและสร้างสตริงกลับจากสตริง


2
คำตอบนี้สามารถใช้คำอธิบายเพิ่มเติมและลิงก์ไปยังเอกสารที่เกี่ยวข้องได้
pdoherty926

4

วิธีที่เร็วที่สุดคือ 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

ขอแนะนำให้ใช้โมดูลPyPiregexหากคุณวางแผนที่จะจับคู่คลาสคุณสมบัติ Unicode เฉพาะ ไลบรารีนี้ได้รับการพิสูจน์แล้วว่ามีเสถียรภาพมากขึ้นโดยเฉพาะการจัดการข้อความขนาดใหญ่และให้ผลลัพธ์ที่สอดคล้องกันในเวอร์ชัน Python ต่างๆ สิ่งที่คุณต้องทำคืออัปเดตอยู่เสมอ

หากคุณติดตั้ง (โดยใช้pip intall regexหรือpip3 install regex) คุณอาจใช้ไฟล์

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

เพื่อเอาชิ้นทุก 1 หรือมากกว่าตัวละครอื่น ๆ กว่าตัวอักษร Unicode textจาก เห็นการสาธิตหลามออนไลน์ คุณอาจใช้"".join(regex.findall(r'\p{L}+', 'ABCŁąć1-2!Абв3§4“5def”'))เพื่อให้ได้ผลลัพธ์เดียวกัน

ใน Python reเพื่อให้ตรงกับตัวอักษร Unicode ใด ๆ อาจใช้[^\W\d_]โครงสร้าง ( ตรงกับตัวอักษร Unicode ใด ๆ ? )

ดังนั้นหากต้องการลบอักขระที่ไม่ใช่ตัวอักษรทั้งหมดคุณอาจจับคู่ตัวอักษรทั้งหมดและเข้าร่วมผลลัพธ์:

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

หรือลบตัวอักษรทั้งหมดนอกเหนือจากที่จับคู่ด้วย [^\W\d_] :

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

ดูออนไลน์สาธิต regex อย่างไรก็ตามคุณอาจได้รับผลลัพธ์ที่ไม่สอดคล้องกันใน Python เวอร์ชันต่างๆเนื่องจากมาตรฐาน Unicode กำลังพัฒนาและชุดของอักขระที่จับคู่\wจะขึ้นอยู่กับเวอร์ชัน Python regexขอแนะนำให้ใช้ไลบรารีPyPi เพื่อให้ได้ผลลัพธ์ที่สม่ำเสมอ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.