ครบชุดเครื่องหมายวรรคตอนสำหรับ Python (ไม่ใช่แค่ ASCII)


40

มีรายชื่อหรือห้องสมุดที่มีเครื่องหมายวรรคตอนทั้งหมดที่เราอาจพบเจอหรือไม่?

ปกติฉันจะใช้string.punctuationแต่เครื่องหมายวรรคตอนบางตัวไม่รวมอยู่ในตัวอย่าง:

>>> "'" in string.punctuation
True
>>> "’" in string.punctuation
False


9
@airstrike ไม่ไม่เลย
samuelbrody1249

คำตอบ:


54

คุณอาจทำได้ดีกว่าด้วยการตรวจสอบนี้:

>>> import unicodedata
>>> unicodedata.category("'").startswith("P")
True
>>> unicodedata.category("’").startswith("P")
True

หมวดหมู่ Unicode P *ใช้สำหรับเครื่องหมายวรรคตอนโดยเฉพาะ:

คอนเนคเตอร์ (Pc), เส้นประ (Pd), คำพูดเริ่มต้น (Pi), คำพูดสุดท้าย (Pf), เปิด (Ps), ปิด (Pe), ปิด (Pe), อื่น ๆ (Po)

ในการเตรียมคอลเลกชันที่ละเอียดถี่ถ้วนซึ่งคุณสามารถใช้สำหรับการตรวจสอบการเป็นสมาชิกที่รวดเร็วในภายหลังให้ใช้ความเข้าใจชุด:

>>> import sys
>>> from unicodedata import category
>>> codepoints = range(sys.maxunicode + 1)
>>> punctuation = {c for i in codepoints if category(c := chr(i)).startswith("P")}
>>> "'" in punctuation
True
>>> "’" in punctuation
True

การแสดงออกที่ได้รับมอบหมายที่นี่ต้องใช้ Python 3.8 ขึ้นไปเทียบเท่ากับ Python รุ่นเก่า:

chrs = (chr(i) for i in range(sys.maxunicode + 1))
punctuation = set(c for c in chrs if category(c).startswith("P"))

ระวังว่าบางส่วนของตัวละครอื่น ๆ ในstring.punctuationเป็นจริงใน Unicode หมวดหมู่สัญลักษณ์ มันง่ายที่จะเพิ่มสิ่งเหล่านี้เข้าด้วยหากคุณต้องการ


คำจำกัดความที่สมเหตุสมผลของ "เครื่องหมายวรรคตอน" จะรวมหมวดหมู่ "สัญลักษณ์" ของ Unicode Sc (สกุลเงินเช่น$), Sk (ตัวดัดแปลง, ชอบ^), Sm (คณิตศาสตร์, ชอบ+หรือ<) และบางที (อื่น ๆ เช่น©)
dan04

3
@ dan04 นั่นคือสิ่งที่พาราสุดท้ายของคำตอบที่กล่าวถึง แน่นอนว่าคนอื่นสามารถปรับรหัสนี้เพื่อรวม / ไม่รวมหมวดหมู่ขึ้นอยู่กับกรณีการใช้งานของตนเอง
Wim

16

คำตอบที่โพสต์โดย wimนั้นถูกต้องหากคุณต้องการตรวจสอบว่าตัวละครนั้นเป็นตัวอักษรวรรคตอนหรือไม่

หากคุณต้องการรายการอักขระเครื่องหมายวรรคตอนทั้งหมดตามที่ชื่อคำถามของคุณแนะนำคุณสามารถใช้สิ่งต่อไปนี้:

import sys
from unicodedata import category
punctuation_chars =  [chr(i) for i in range(sys.maxunicode) 
                             if category(chr(i)).startswith("P")]

2

คำตอบโดย wimนั้นยอดเยี่ยมถ้าคุณสามารถเปลี่ยนรหัสของคุณเพื่อใช้ฟังก์ชัน

แต่ถ้าคุณต้องใช้inโอเปอเรเตอร์ (ตัวอย่างเช่นคุณโทรเข้ารหัสห้องสมุด) คุณสามารถใช้การพิมพ์เป็ด:

import unicodedata
class DuckType:
    def __contains__(self,s):
        return unicodedata.category(s).startswith("P")
punct=DuckType()
#print("'" in punct,'"' in punct,"a" in punct)

1

ดูเหมือนว่าจะเป็นงานที่ดีสำหรับนิพจน์ทั่วไป (regexp)

    import re
    text = re.sub(r"[^\w\s]", "", str(text), flags=re.UNICODE)

ที่นี่ regexp จับคู่ทุกอย่างยกเว้นช่องว่างหรืออักขระคำ การตั้งค่าสถานะre.UNICODEใช้เพื่อจับคู่กับชุดอักขระ Unicode ทั้งหมด


ไม่สามารถใช้ได้กับหลายภาษา:>>> text="Den som dræber - fanget" >>> re.sub(r"[^\w\s]", "", str(text), flags=re.UNICODE) 'Den som dr\xc3ber fanget'
samuelbrody1249

1
@ samuelbrody1249 คุณหมายถึงอะไรมันใช้งานไม่ได้? มันทำงานได้ในตัวอย่างของคุณ (การ\xc3หลบหนีเป็นสิ่งที่นำเสนอที่ไม่เกี่ยวข้องกับการลอกเครื่องหมายวรรคตอน)
lenz

1
@lenz \xc3ไม่ถูกต้อง Unicode เข้ารหัสของæ; ถ้าคุณพิมพ์คุณสามารถยืนยันได้ว่ามันเป็นstr(text) \xc3\xa6จริงๆแล้ว\xc3ดูเหมือนจะไม่ใช่ codepoint ที่สมบูรณ์
Federico Poloni

6
อ้อเข้าใจแล้ว. ดูเหมือนว่าคุณทั้งสองกำลังใช้ Python 2 อยู่ที่ไหนstrเป็นสตริงไบต์ คุณควรเปลี่ยนไปใช้ Python 3 อย่างแน่นอนเพราะ Unicode เป็นฝันร้ายใน Py2 สำหรับฉันstr('æ')แสดงเป็น'æ'และascii('æ')แสดงเป็น'\xe6'codepoint ที่ถูกต้อง b'\xc3\xa6'เป็นการเข้ารหัสแบบ UTF-8 'æ'แต่นี่ไม่ใช่สิ่งที่คุณต้องการใช้งาน
lenz

0

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

อย่างไรก็ตามreโมดูลไลบรารีมาตรฐานไม่ได้ให้การสนับสนุน Unicode แบบขยาย สำหรับสิ่งที่คุณต้องการregexโมดูลที่มีอยู่ใน PyPI ( pip install regex):

>>> import regex as re
>>> re.match("\p{Punctuation}", "'")
<regex.Match object; span=(0, 1), match="'">
>>> re.match("\p{Punctuation}", "’")
<regex.Match object; span=(0, 1), match='’'>

ภาพรวมที่ดีของทุกชนิดที่แตกต่างกันของคุณสมบัติ Unicode คุณสามารถค้นหาได้โดยใช้การแสดงออกปกติมีให้ที่นี่ นอกเหนือจากคุณสมบัติการแสดงผลปกติเพิ่มเติมเหล่านี้ซึ่งได้รับการบันทึกไว้ในหน้าแรกของ PyPI นั้นregexจงใจให้ API เดียวกับreดังนั้นคุณคาดว่าจะใช้reเอกสารประกอบของตัวเองเพื่อหาวิธีใช้ทั้งสองอย่าง

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