เฉลยโจทย์: การประมวลผลข้อมูลจากไฟล์#

โจทย์การเขียนเรกเอกซ์#

ข้อ 1: ทะเบียนรถ#

  • เรกเอกซ์: [A-Z]{2}\d{3,4}

  • คำอธิบาย:

    • ^[A-Z]{2}: ขึ้นต้นด้วยอักษรภาษาอังกฤษตัวพิมพ์ใหญ่ 2 ตัว

    • \d{3,4}: ตามด้วยตัวเลข 3 หรือ 4 ตัว

ข้อ 2: รหัสสีแบบ 6 หลักในระบบฐานสิบหก#

  • เรกเอกซ์: #[0-9a-fA-F]{6}

  • คำอธิบาย:

    • [0-9a-fA-F]{6}: ตามด้วยตัวเลข 0-9 หรือ a-f หรือ A-F จำนวน 6 ตัว

ข้อ 3: ชื่อคนไทยที่ประกอบด้วยตัวอักษรไทยเท่านั้น#

  • เรกเอกซ์: [ก-์]{2,}

  • คำอธิบาย:

    • ^[ก-์]{2,}: ต้องมีตัวอักษรไทย 2 ตัวหรือมากกว่า

ข้อ 4 ชื่อผู้ใช้งาน#

  • เรกเอกซ์: [a-z][a-z0-9_.]*[a-z0-9]

  • คำอธิบาย:

    • [a-z]: ต้องขึ้นต้นด้วยอักษรภาษาอังกฤษตัวพิมพ์เล็ก

    • [a-z0-9_.]*: ประกอบด้วยอักษรภาษาอังกฤษตัวพิมพ์เล็ก ตัวเลข และเครื่องหมาย _ หรือ . ได้หลายตัว

    • [a-z]: ลงท้ายด้วยอักษรภาษาอังกฤษตัวพิมพ์เล็ก หรือตัวเลข

ข้อ 5 เบอร์โทรศัพท์ไทย#

  • เรกเอกซ์: 0\d{9}

  • คำอธิบาย:

    • ^0: ขึ้นต้นด้วยเลข 0

    • \d{9}: ตามด้วยตัวเลข 9 ตัว

ข้อ 6 ที่อยู่#

  • เรกเอกซ์: [ก-ฮ0-9/ ]+

  • คำอธิบาย:

    • ^[ก-ฮ0-9/]+: ต้องประกอบด้วยตัวอักษรไทย ตัวเลข และเครื่องหมาย / อย่างน้อยหนึ่งตัว

ข้อ 7 สกุลไฟล์#

  • เรกเอกซ์: [a-zA-Z].*\.((txt)|(csv)|(json))$

  • คำอธิบาย:

    • [a-zA-Z]: ต้องขึ้นต้นด้วยตัวอักษรภาษาอังกฤษตัวเล็กหรือตัวใหญ่

    • .*: แทนตัวอักษรใดก็ได้ 0 ตัวหรือมากกว่า

    • \.((txt)|(csv)|(json)): นามสกุลไฟล์ต้องเป็น .txt, .csv หรือ .json

ข้อ 8 อีเมลล์#

  • เรกเอกซ์: [a-zA-Z0-9]+@(gmail|yahoo)\.com

  • คำอธิบาย:

    • [a-zA-Z0-9]+: ขึ้นต้นด้วยตัวอักษร ตัวเลข อย่างน้อย 1 ตัว

    • @(gmail|yahoo)\.com: ลงท้ายด้วย @gmail.com หรือ @yahoo.com

ข้อ 9 วันเดือน#

  • เรกเอกซ์: ^(0[1-9]|[12][0-9]|3[01])/(0[1-9]|1[0-2])$

  • คำอธิบาย:

    • ^(0[1-9]|[12][0-9]|3[01]): วันที่ต้องอยู่ระหว่าง 01-09 หรือ 10-29 หรือ 30-31

    • /(0[1-9]|1[0-2]): เดือนต้องอยู่ระหว่าง 01-09 หรือ 10-12

ข้อ 10 ขึ้นต้นอะไรก็ได้แต่ต้องลงท้ายด้วยสระ า#

  • เรกเอกซ์: ([ก-์]*[^เ ][ก-ฮ][่-๋]?า)|([ก-ฮ][่-๋]?า)

  • คำอธิบาย: แบ่งเป็นสองส่วนหลัก โดยใช้ตัวแบ่งคือ |

    • ส่วนแรก: ([ก-์]*[^เ ][ก-ฮ][่-๋]?า) เพื่อจับคำที่มีหลายพยางค์

      • ([ก-์]*): จับคู่ตัวอักษรไทยตั้งแต่ตัวใดตัวหนึ่งไปจนถึงตัว “์” (ไม้ไต่คู้) หรืออักษรใดๆ ในช่วงนี้ ได้ตั้งแต่ 0 ตัวขึ้นไป

      • [^เ ]: ต้องไม่ใช่สระ “เ” หรือช่องว่าง ( ) ตัวนี้ใช้เพื่อป้องกันการจับคู่คำที่มี “เ” นำหน้า เช่น “เกา” ไม่ให้ถูกจับคู่

      • [ก-ฮ]: จับคู่ตัวอักษรไทยในช่วงตั้งแต่ “ก” ถึง “ฮ” ที่ตามหลังตัวที่ไม่ใช่ “เ”

      • [่-๋]?: จับคู่รูปวรรณยุกต์ไทย เช่น ไม้เอก ไม้โท เป็นต้น แต่มีหรือไม่มีก็ได้

      • : จับคู่สระ “า” ซึ่งเป็นตัวอักษรสุดท้ายของคำ

    • ส่วนที่สอง: ([ก-ฮ][่-๋]?า) เพื่อจับคำพยางค์เดียวที่ออกเสียงเป็น “า”

      • [ก-ฮ]: จับคู่ตัวอักษรไทยตั้งแต่ “ก” ถึง “ฮ”

      • [่-๋]?: จับคู่รูปวรรณยุกต์ไทย (ไม้เอก, ไม้โท, ฯลฯ) มีหรือไม่มีก็ได้

      • : จับคู่สระ “า” เป็นตัวสุดท้ายของคำ

โจทย์ปัญหาการประมวลผลข้อมูลจากไฟล์#

ข้อ 1#

import re
from collections import Counter

# สร้าง Counter เพื่อเก็บค่า part-of-speech tags และคำ
pos_counter = Counter()
word_counter = Counter()

# กำหนดรูปแบบ regex เพื่อค้นหาคำและ part-of-speech tags
pattern = r'(\S+?)_([A-Za-z$]+)'

# เปิดไฟล์และอ่านไฟล์ทีละบรรทัด
with open('obama.txt', 'r', encoding='utf-8') as file:
    for line in file:
        # ค้นหาคำทั้งหมดที่ตรงกับ pattern ในบรรทัดปัจจุบัน
        matches = re.findall(pattern, line)
        
        # อัพเดต Counter ด้วยค่าที่พบ
        pos_counter.update(pos for word, pos in matches)
        word_counter.update(word for word, pos in matches)

# ดึงข้อมูล part-of-speech tags ที่มีความถี่สูงสุดและคำ 100 คำแรก
pos_freq = pos_counter.most_common()
top_100_word = word_counter.most_common(100)

# แสดงผลลัพธ์
print("\nความถี่ของ Part-of-Speech Tags:")
for pos, freq in pos_freq:
    print(f"{pos}: {freq}")

print("\nคำ 100 คำแรกที่มีความถี่สูงสุด:")
for word, freq in top_100_word:
    print(f"{word}: {freq}")

ข้อ 2#

ข้อ 2.1#

import re
def is_name_like(word):
    pattern = r'^[A-Z][a-z]*$'
    # ใช้ re.match เพื่อตรวจสอบว่าคำตรงกับแพตเทิร์นหรือไม่ และแปลงผลลัพธ์เป็นบูลีน
    return bool(re.match(pattern, word))

ข้อ 2.2#

def get_all_names(sentence):
  pattern = r'\b[A-Z][a-z]*\b'
  # ใช้ re.findall เพื่อค้นหาคำทั้งหมดที่ตรงกับ pattern ในประโยค
  names = re.findall(pattern, sentence)
  return names

ข้อ 2.3#

def censor_names(sentence):
  pattern = r'\b[A-Z][a-z]*\b'
  # ใช้ re.sub เพื่อแทนที่คำที่ตรงกับ pattern ด้วย "XXX"
  censored_sentence = re.sub(pattern, 'XXX', sentence)
  return censored_sentence

ข้อ 3#

def autoanswer(question):
    # ตรวจสอบว่าประโยคขึ้นต้นด้วย "Do" หรือ "Does" หรือไม่
    match = re.match(r'^(Do|Does) (.*)', question)
    if match:
        # ถ้าเป็นประโยคคำถามที่ขึ้นต้นด้วย "Do" หรือ "Does"
        verb = match.group(1)
        rest_of_sentence = match.group(2)
        # แทนที่ "Do" หรือ "Does" ด้วย "do" หรือ "does" ตามลำดับ
        response_verb = "do" if verb == "Do" else "does"
        # สร้างคำตอบในรูปแบบ "Yes, ... do/does ..."
        return f"Yes, {rest_of_sentence.split()[0]} {response_verb} {rest_of_sentence[len(rest_of_sentence.split()[0])+1:]}."
    else:
        # ถ้าไม่ใช่ประโยคคำถามที่ขึ้นต้นด้วย "Do" หรือ "Does"
        return f"{question}?"

ข้อ 4#

ข้อ 4.1#

import re

# อ่านไฟล์ nyt_eng_200001
with open('small_nyt_eng_200001', 'r') as file:
    s = file.read()

# หาคำที่ขึ้นต้นด้วยตัว k
pattern_start_k = r'\bk\w*'
start_k_words = re.findall(pattern_start_k, s)

# หาคำที่ตัวที่สองเป็นตัว k
pattern_second_k = r'\b\w*k\w*'
second_k_words = re.findall(pattern_second_k, s)

# หาคำที่ลงท้ายด้วยตัว k
pattern_end_k = r'\b\w*k\b'
end_k_words = re.findall(pattern_end_k, s)

# นับจำนวนคำที่ตรงกับแต่ละ pattern
total_words = len(start_k_words) + len(second_k_words) + len(end_k_words)

# แสดงผลลัพธ์
print("จำนวนคำที่ขึ้นต้นด้วยตัว k:", len(start_k_words))
print("จำนวนคำที่ตัวที่สองเป็นตัว k:", len(second_k_words))
print("จำนวนคำที่ลงท้ายด้วยตัว k:", len(end_k_words))
print("จำนวนคำที่มีคุณสมบัติตรงตามที่กำหนดทั้งหมด:", total_words)

ข้อ 4.2#

import re

# อ่านไฟล์ nyt_eng_200001
with open('small_nyt_eng_200001', 'r') as file:
    s = file.read()

# หาคำที่ขึ้นต้นด้วยตัว k
pattern_start_k = r'\bk\w*'
start_k_words = set(re.findall(pattern_start_k, s))

# หาคำที่ตัวที่สองเป็นตัว k
pattern_second_k = r'\b\w{k}\w*'
second_k_words = set(re.findall(pattern_second_k, s))

# หาคำที่ลงท้ายด้วยตัว k
pattern_end_k = r'\b\w*k\b'
end_k_words = set(re.findall(pattern_end_k, s))

# รวมคำที่ไม่ซ้ำจากทั้งสามชุด
all_k_words = start_k_words.union(second_k_words).union(end_k_words)

# นับจำนวนคำที่ไม่ซ้ำกัน
total_unique_words = len(all_k_words)

# แสดงผลลัพธ์
print("จำนวนคำที่ขึ้นต้นด้วยตัว k (ไม่ซ้ำ):", len(start_k_words))
print("จำนวนคำที่ตัวที่สองเป็นตัว k (ไม่ซ้ำ):", len(second_k_words))
print("จำนวนคำที่ลงท้ายด้วยตัว k (ไม่ซ้ำ):", len(end_k_words))
print("จำนวนคำที่มีคุณสมบัติตรงตามที่กำหนดทั้งหมด (ไม่ซ้ำ):", total_unique_words)

ข้อ 5#

import re

def find_names(announcement_file):
    # เปิดไฟล์ประกาศเพื่ออ่านข้อมูล
    with open(announcement_file, 'r', encoding='utf-8') as file:
        text = file.read()
      
    # กำหนด pattern ของ regex เพื่อจับชื่อในวงเล็บที่มีคำนำหน้าว่า นาย นางสาว หรือ นาง
    pattern = r'\((นาย|นางสาว|นาง)(\S+)'
    
    # ใช้ re.findall เพื่อหาข้อความทั้งหมดที่ตรงกับ pattern ใน text
    # re.findall จะคืนค่าเป็นลิสต์ของ tuple ที่แต่ละ tuple มีสองส่วนคือคำนำหน้าและชื่อ
    matches = re.findall(pattern, text)
    
    # สร้างลิสต์เปล่าเพื่อเก็บชื่อผู้ชายและผู้หญิง
    male_names = []
    female_names = []
    
    # ลูปผ่านผลลัพธ์ที่จับได้จาก regex
    for title, name in matches:
        # ถ้าคำนำหน้าเป็น "นาย" ให้เพิ่มชื่อไปยังลิสต์ male_names
        if title == "นาย":
            male_names.append(name)
        # ถ้าคำนำหน้าเป็น "นางสาว" หรือ "นาง" ให้เพิ่มชื่อไปยังลิสต์ female_names
        else:
            female_names.append(name)
    
    # คืนค่าลิสต์ชื่อผู้ชายและผู้หญิง
    return male_names, female_names

ข้อ 6#

# import โมดูล regular expression เพื่อใช้ในการหาคำ
import re 

def count_en_th_words(word_list):
    """
    Example:
    >>> count_en_th_words(['รองเท้า', 'ไม่', 'match', 'กับ', 'coat', 'เลย'])
    {'en': 2, 'th': 4}
    """
    # สร้าง dict ที่มีค่าเริ่มต้นของจำนวนคำภาษาอังกฤษและภาษาไทยเป็น 0
    result_dict = {'en': 0, 'th': 0}
    # วนลูปผ่านคำในรายการคำ
    for w in word_list:
        # ตรวจสอบว่าคำเป็นภาษาอังกฤษหรือไม่
        if re.search('[a-zA-Z]', w):
            # ถ้าใช่ เพิ่มจำนวนคำภาษาอังกฤษขึ้น 1
            result_dict['en'] += 1
        else:
            # ถ้าไม่ใช่ เพิ่มจำนวนคำภาษาไทยขึ้น 1
            result_dict['th'] += 1

    return result_dict