import re #### Gamble Clean Words GAMBLE_WORDS = [ "พนัน", "แทงบอล", "แทง", "บาคารา", "บา คา รา", "เกมพนัน", "คาสิโน", "คา สิ โน", "หวย", "สล็อต", "กาสิโน", "casino", "slot", "เลขเด็ด", "สูตรหวย", "a s i n o", "sbobet", "fun88", "ufabet", "บาคาร่า", "บา คา ร่า", "รูเล็ต", "ทำนายฝัน", "เลขเด่น", "สรุปผลบอล", "ไฮไลท์ฟุตบอล", "วิเคราะห์บอล", "ดูบอลสด", "พรีเมียร์ลีก", "บอลประจำวัน", "บอลเต็ง", "บอลเด็ด", "องค์ลงรวย", "สูตรปลาตะเพียน", "สามตัวตรง", "วิเคราะห์ข้อมูลล่าง", "ต่อ ครึ่งลูก", "ครึ่งลูกลบ", "เสมอควบครึ่ง", "ครึ่งควบลูก", ] #### Sale Clean Words SALE_SKIP_WORDS = [ "สอบราคา", "จัดซื้อจัดจ้าง", "ชมรม", "สมาคม", "นักลงทุน", "นักการตลาด", "ของกลาง", "การลงทุน", "นักวิเคราะห์", "ขายให้แก่ประชาชน", "การลดต้นทุน", "การเสนอราคา", "กระทรวง", "ตลาดหลักทรัพย์", "ยอดขายไม่ดี", "ยอดขายไม่ค่อยดี", "ผู้ประกอบการธุรกิจ", "ออกใบอนุญาต", "ผู้ประกอบกิจการ", ] SALE_URL_WORDS = [ "alibaba.com", "shopee.co.th", "lazada.com", "DocPlayer.net", "Alibaba", "AliExpress", "Aliexpress", "TripAdvisor", "jobbkk.com", ] SALE_WORDS = [ "ขาย", "ซ่อม", "ราคา", "มือสอง", "เช่า", "ครีม", "ฝ้ากระ", "จุดด่างดำ", "รับส่วนลด", "โปรโมชั่น", "กวดวิชา", "ติวเตอร์", "SEO", "คอร์สเรียน SEO", "จำหน่าย", "ทัวร์", "สินค้ามาใหม่", "สินค้าทั้งหมด", "รีวิวสินค้า", "เคสกันกระแทก", "ประกาศ", "ลงขายของ", "เลือกขนาด", "บริการจัดส่ง", "จัดอันดับ", "คาราโอเกะ", "จำหน่าย", "หาเงินออนไลน์", "สั่งซื้อ", "ลดกระหนำ่", "รหัส", "ลงประกาศฟรี", "หยิบใส่ตะกร้า", "สนใจ", "ซื้อ", "สินค้า", "ผลิตภัณฑ์", ] #### Rent Clean Words RENT_SKIP_WORDS = [ "สอบราคา", "จัดซื้อจัดจ้าง", "ชมรม", "สมาคม", "นักลงทุน", "นักการตลาด", "ของกลาง", "การลงทุน", "นักวิเคราะห์", "ขายให้แก่ประชาชน", "การลดต้นทุน", "การเสนอราคา", "กระทรวง", "ตลาดหลักทรัพย์", ] RENT_WORDS = [ "บ้านมือสอง", "ให้เช่า", "เช่า", "บ้านเดี่ยว", "อพาร์ทเม้นท์", "อสังหาริมทรัพย์", "เพนท์เฮ้าส์", "ทาวน์เฮ้าส์", ] #### Script Clean Words SCRIPT_WORDS = [ "function", "var", "click", "margin", "width", "height", "return", "else", "alert", "
", "href", ] #### Garbage Clean Words GARBAGE_WORDS = [ "โหงวเฮ้ง", "ครีมฟอกสี", "ครีมผิวขาว", "ฟอกสี", "ไวท์เทนนิ่งครีม", "ครีมไวท์เทนนิ่ง", "ครีมลบฝ้ากระ", "รับสร้างบ้าน", "ครีมโรคสะเก็ดเงิน", "บริการจองตั๋ว", "บริการรีดผ้า", "อาหารเสริมลดน้ำหนัก", "ยาลดน้ำหนัก", "ลดไขมัน", "ผิงโซดา", "สร้างบ้าน", "ช่างกุญแจ", "ช่างโลหะ", "ช่างโยธา", "ช่างเครื่องยนต์", "ช่างไม้", "ช่างกลโรงงาน", "ช่างไฟฟ้า", "ปรสิต", "หนอน", "เวิร์ม", ] #### Football teams FOOTBALL_TEAMS = [ "ยูเวนตุส", "อินเตอร์ มิลาน", "นาโปลี", "เอซี มิลาน", "ลาซิโอ", "โรม่า", "กัลโซ่", "เซเรีย", "ปาร์ม่า", "เอฟเวอร์ตัน", "ซันเดอร์แลนด์", "ลิเวอร์พูล", "แมนเชสเตอร์", "นิวคาสเซิล", "เชลซี", "อาร์เซนอล", "คลิสตัลพาเลช", "เซาแทมป์ตัน", "เซาแธมป์ตัน", "เชฟฟิลด์", "ฟอเรสต์", "เบอร์ตัน", "เบรนท์ฟอร์ด", "ฟูแล่ม", "ไฮไลท์ฟุตบอล", "เลบันเต้", "บาร์เซโลน่า", "เรอัล มาดริด", "เอสปันญ่อล", ] #### Hotels Advertising HOTEL_AD = [ "โรงแรมอันดับ", "ที่พักแบบพิเศษอันดับ", "สถานที่พักอันดับ", "สถานที่พักคุ้มค่าอันดับ", "โรงแรมใกล้กับ", "โรงแรมที่ใกล้", "โรงแรม 4 ดาว", "โรงแรม 3 ดาว", "ที่พักพร้อมอาหารเช้า", "โรงแรมราคาถูก", "โรงแรมหรู", ] ######### # PRE-COMPILE REGEX to object for speed up processing. ######### # ----------------------------------------------------- # Remove useless row that make overhead in regex processing # Unusual row - line size too large # if there are 3 large lines ( 500 characters each) TOOLARGE_LINE_PATTERN = ".{1500}" TOOLARGE_RE = re.compile(TOOLARGE_LINE_PATTERN, re.MULTILINE) NONECHAR_PATTERN = "๮|๞|๨|๡|๷|๻|๫|͹" NONECHAR_RE = re.compile(NONECHAR_PATTERN, re.MULTILINE) NONE_TONE_MARK_PATTERN = "ก าหนด|เป าหมาย|พ ฒนา|ค ณภาพ|ว จ ย|ค ณล กษณะ|ต างๆ|เป น |ให |บร หาร|ปร บปร ง|ใหม|อย าง|เง น" NONE_TONE_MARK_RE = re.compile(NONE_TONE_MARK_PATTERN, re.MULTILINE) # ----------------------------------------------------- GAMBLE_PATTERN = "|".join(GAMBLE_WORDS) GAMBLE_RE = re.compile(GAMBLE_PATTERN, re.MULTILINE) FOOTBALL_PATTERN = "|".join(FOOTBALL_TEAMS) FOOTBALL_RE = re.compile(FOOTBALL_PATTERN, re.MULTILINE) HOTEL_AD_PATTERN = "|".join(HOTEL_AD) HOTEL_AD_RE = re.compile(HOTEL_AD_PATTERN, re.MULTILINE) SALE_URL_PATTERN = "|".join(SALE_URL_WORDS) SALE_URL_RE = re.compile(SALE_URL_PATTERN, re.MULTILINE) SALE_SKIP_PATTERN = "|".join(SALE_SKIP_WORDS) SALE_SKIP_RE = re.compile(SALE_SKIP_PATTERN, re.MULTILINE) SALE_PATTERN = "|".join(SALE_WORDS) SALE_RE = re.compile(SALE_PATTERN, re.MULTILINE) RENT_SKIP_PATTERN = "|".join(RENT_SKIP_WORDS) RENT_SKIP_RE = re.compile(RENT_SKIP_PATTERN, re.MULTILINE) RENT_PATTERN = "|".join(RENT_WORDS) RENT_RE = re.compile(RENT_PATTERN, re.MULTILINE) JSON_PATTERN = r"\s*\"(?:\w)*\"\s*:" JSON_RE = re.compile(JSON_PATTERN, re.MULTILINE) SCRIPT_PATTERN = r"\b" + "|".join(SCRIPT_WORDS) + r"\b" SCRIPT_RE = re.compile(SCRIPT_PATTERN, re.MULTILINE) GARBAGE_PATTERN = "|".join(GARBAGE_WORDS) GARBAGE_RE = re.compile(GARBAGE_PATTERN, re.MULTILINE) GHOST_PATTERN = "เธฃเน|เธเธญ|เธเน|เธฐเธ|เธฅเธฐ|เธซเธฒ|เธญเธฒ|เธดเธ|เธตเธข|เธญเน|เธญเธ|เธดเน|เธฑเธ|เธกเน|เธฒเธ|เธชเน|เน€เธ" GHOST_RE = re.compile(GHOST_PATTERN, re.MULTILINE) HEX_PATTERN = "(?>)?|<<(?:[ ]\d{0,6}[ ]\-[ ]\d{0,6})+[ ].{0,100}" PAGE_RE = re.compile(PAGE_PATTERN, re.MULTILINE) EMBEDDED_SERVER_PATTERN = "<%[ ]*[^%]*%>|<%.*" EMBEDDED_SERVER_RE = re.compile(EMBEDDED_SERVER_PATTERN, re.MULTILINE) U_PATTERN = "\uFEFF|\u00AD|[\u200A-\u200F]|\uFFFD|[\uE000-\uF8FF]|[\u202A-\u202C]|\u0092|[\u0091-\u0096]|\u2028|\u2066|\u2069|\u008d|\u0081|\u008E|" U_RE = re.compile(U_PATTERN, re.MULTILINE) BLOCK_PATTERN = "(?:\[[^\]]*\])|(?:«[^»]*»)|(?:<<([^>]*)>>)" BLOCK_RE = re.compile(BLOCK_PATTERN, re.MULTILINE) EMAIL_PATTERN = "(?:(?:([Ee]?mail|อีเมล์)[ ]{0,2}:?[ ]{0,5})?)[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" EMAIL_RE = re.compile(EMAIL_PATTERN, re.MULTILINE) URL_PATTERN = r"\b(?:(?:https?|ftp)://[^\s/$\.\?#].[^\s]*)\b|\b(?:www\.?)?(?:(?:[\w-]*)\.)*(?:com|net|org|info|biz|me|io|co|asia|xyz|th|cn|in|uk|jp|ru)\b" URL_RE = re.compile(URL_PATTERN, re.MULTILINE) MENU1_PATTERN = "\|(?:[^\|\n]*\|)+.*" MENU1_RE = re.compile(MENU1_PATTERN, re.MULTILINE) MENU2_PATTERN = "\|(?:[^\|\n]*\|)+" MENU2_RE = re.compile(MENU2_PATTERN, re.MULTILINE) MENU3_PATTERN = "(?:(?:[^/\n]*/){4,}.*)" MENU3_RE = re.compile(MENU3_PATTERN, re.MULTILINE) MENU4_PATTERN = "^[^\n]{0,20}[ ]{0,2}[>»\\\\].*" MENU4_RE = re.compile(MENU4_PATTERN, re.MULTILINE) HASHTAG_PATTERN = "#\d*[ ].{0,300}|#(?:(?:[^ \n]*)[ ]?)+|Tag Archives[ ]{0,2}:.{0,300}|Posts Tagged[ ]{0,2}:.{0,300}|HASTAG[ ]{0,2}:.{0,300}|Tag[s]?[ ]{0,2}:.{0,300}|Tagged[ ].{0,300}" HASHTAG_RE = re.compile(HASHTAG_PATTERN, re.MULTILINE) SIDEBAR_PATTERN = ".{0,40}(?:(?:\[|\()\d{0,9}(?:\]|\))(?:[ ]{0,2})?,?)" SIDEBAR_RE = re.compile(SIDEBAR_PATTERN, re.MULTILINE) MARKUP_PATTERN = "\{\{[^\}]*\}\}|\{\{.*" MARKUP_RE = re.compile(MARKUP_PATTERN, re.MULTILINE) IFRAME_PATTERN = "\s*|?| |{\s*document\..*|SELECT.*FROM.*WHERE.*| bool: # ---- Clean too large unused lines # Limit matches list to 2 items only, enough matches = TOOLARGE_RE.findall(text)[:2] # Classify as toolarge row if number of matches = 2 if len(matches) == 2: return True # ---- Clean none characters row # Limit matches list to 25 items matches = NONECHAR_RE.findall(text)[:25] # Classify as none character row if number of matches = 25 if len(matches) == 25: return True # ---- Clean none tone mark row # Limit matches list to 25 items matches = NONE_TONE_MARK_RE.findall(text)[:25] # Classify as none tone mark row if number of matches = 25 if len(matches) == 25: return True # ---- Clean Gamble ~ 9.2% of mC4 data # if found gamble word 2 times in a row, classify as gamble row # remove the row # Limit matches list to 2 items only, enough matches = GAMBLE_RE.findall(text)[:2] # Classify as gamble if number of matches = 2 if len(matches) == 2: return True # ---- Clean Football data # if found gamble word 4 times in a row, classify as football data # remove the row # Limit matches list to 4 items only matches = FOOTBALL_RE.findall(text)[:4] if len(matches) == 4: return True # ---- Clean Hotel Advertising # if found hotel word 4 times in a row, classify as Hotel Ad. data # remove the row # Limit matches list to 4 items only, enough matches = HOTEL_AD_RE.findall(text)[:4] if len(matches) == 4: return True # ---- Clean Sale ~26% of mC4 data # Sale row data is diverse, # so the regex is not used in this case. # Rules: # 1. Remove row if it contains common specific Sale's URL # 2. Skip to next clean rule if it contains specific keywords, eg. "สอบราคา", "จัดซื้อจัดจ้าง, etc." # 3. If not found keywords in (2) then scan the row with sale keywords, if there are at leat 3 sale kewords found then remove the row. if SALE_URL_RE.search(text): return True if not SALE_SKIP_RE.search(text): # Classify as Sale data ( 3 matches, can be adjusted) matches = SALE_RE.findall(text)[:3] if len(matches) == 3: return True # ---- Clean Rent (พวกเช่า ~2% of mC4 data) # Rent use another rules # 1. find skip words in the row. If found, skip to next rule (not remove) # 2. if found rent word 2 times in a row, classify as rent row # remove the row if not RENT_SKIP_RE.search(text): # Limit matches list to 2 items only, enough matches = RENT_RE.findall(text)[:2] if len(matches) == 2: return True # ---- Clean pattern (json like -> "abc": ~.5-1% ) # 99% can classify as gabage: so remove them # match n items to make sure they are garbages n=20, can change matches = JSON_RE.findall(text)[:20] # if match only 20+, classify as garbage if len(matches) == 20: return True # ---- Clean script (Javascript, etc. ~.5% ) # 99% can classify as gabage: so remove them matches = SCRIPT_RE.findall(text)[:10] # Classify as script if number of matches = 10 if len(matches) == 10: return True # ---- Clean garbage (useless or not necessary ~.45%) # classify as gabage: so remove them matches = GARBAGE_RE.findall(text)[:4] # Classify as garbage if number of matches = 4 if len(matches) == 4: return True # ---- Clean ghost language (~0.008% can cancel this clean) # classify as ghost : so remove them matches = GHOST_RE.findall(text)[:4] # Classify as ghost if number of matches = 4 if len(matches) == 4: return True # ---- Clean HEX code # classify as HEX : so remove them matches = HEX_RE.findall(text)[:25] # Classify as HEX if number of matches = 25 if len(matches) == 25: return True return False def clean_mc4_text(text: str) -> str: text = PAGE_RE.sub(" ", text) text = EMBEDDED_SERVER_RE.sub(" ", text) text = U_RE.sub(" ", text) text = EMAIL_RE.sub(" ", text) text = URL_RE.sub(" ", text) text = MENU1_RE.sub(" ", text) text = MENU2_RE.sub(" ", text) text = MENU3_RE.sub(" ", text) text = MENU4_RE.sub(" ", text) text = SIDEBAR_RE.sub(" ", text) text = BLOCK_RE.sub(" ", text) text = HASHTAG_RE.sub(" ", text) text = MARKUP_RE.sub(" ", text) text = IFRAME_RE.sub(" ", text) text = IP_RE.sub(" ", text) text = TEL_RE.sub(" ", text) text = DATE1_RE.sub(" ", text) text = DATE2_RE.sub(" ", text) text = HTML_RE.sub(" ", text) # --- Refinements (in sequence) text = REFINE1_RE.sub(" ", text) text = REFINE2_RE.sub(" ", text) text = REFINE3_RE.sub(" ", text) text = REFINE4_RE.sub(" ", text) text = REFINE5_RE.sub(" ", text) text = REFINE6_RE.sub(" ", text) text = REFINE7_RE.sub(" ", text) text = REFINE8_RE.sub(" ", text) text = REFINE9_RE.sub(" ", text) text = REFINE10_RE.sub(" ", text) text = REFINE11_RE.sub(" ", text) text = REFINE12_RE.sub(" ", text) text = REFINE13_RE.sub(" ", text) text = REFINE14_RE.sub(" ", text) # Split the text into lines and remove any empty lines lines = [line for line in text.split("\n") if line] # Initialize the list with the first line deduplicated_list = [lines[0]] # Iterate over the rest of the lines for i in range(1, len(lines)): # Find the common prefix between this line and the previous line common_prefix = "" for char1, char2 in zip(lines[i], lines[i - 1]): if char1 == char2: common_prefix += char1 else: break # Remove the common prefix from this line and add it to the list deduplicated_list.append(lines[i][len(common_prefix) :]) text = "\n".join(deduplicated_list) # Clean short lines # ( len(line) <= 30 characters , cut this line off) text = "\n".join(line for line in text.split("\n") if len(line) > 30) # ---- The scan row that passes all filter is written to disk # before write to disk, get rid of spaces by change them to single space (' '). text = re.sub("[ ]+", " ", text, 0, re.MULTILINE) text = re.sub("^[ ]", "", text, 0, re.MULTILINE) text = re.sub(r"\n\s*", "\n", text, 0, re.MULTILINE) return text def clean_dataset(dataset: List[Dict[str, str]]) -> List[Dict[str, str]]: """ Description : Call function clean_text to process the whole dataset. Input text : An input dataset having each element as a document in the dataset. Output : A clean dataset. """ for i, data_point in enumerate(dataset): cleaned_text = clean_text(data_point["text"]) if cleaned_text != dataset[i]["text"]: dataset[i]["text"] = cleaned_text dataset[i]["updated_date"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S") return [data_point for data_point in dataset if data_point["text"] != ""] def sorted_by_len(keyword_list): len_keywords = [[len(kw), kw] for kw in keyword_list] return [kw for _, kw in sorted(len_keywords)][::-1] PORN_KEYWORDS = [ "คลิปหลุด", "กระเจี๊ยว", "คลิปโป๊", "หนังโป๊", "หนังโป้", "หนังโป็", "เรื่องเสียว", "ซอยหี", "ชักว่าว", "ท่าหมา", "ขย่มควย", "เล่นเสียว", "ควยใหญ่", "หนังเอ็กซ์", "แหกหี", "เย็ด", ] GAMBLE_KEYWORDS = [ "ufabet", "UFABET", "ล้มโต๊ะ", "เซียนสเต็ป", "บอลเต็ง", "แทงบอล", "คาสิโน", "บาคาร่า", "เว็บสล็อต", "เกมสล็อต", "สล็อตออนไลน์", "คาสิโนออนไลน์", "หวยมาเลย์", "หวยฮานอย", "น้ำเต้าปูปลา", "หวยออนไลน์", "แทงหวย", "หวยหุ้น", "ยิงปลาออนไลน์", "ได้เงินจริง", "บา คา ร่า", ] SPAM_MOVIE_KEYWORDS = [ "ดูหนังออนไลน์", "หนังออนไลน์", "เว็บดูหนัง", "หนังชนโรง", "หนังใหม่ชนโรง", "เสียงไทย", "เสียงญี่ปุ่น", "เสียงอังกฤษ", ] SPAM_LIKE_KEYWORDS = [ "ปั้มไลค์", "รับจ้างกดไลค์", "จ้างไลค์", "ปั๊มไลค์", "ปั่นไลค์", "เพิ่มไลค์", "ซื้อไลค์", ] CODE_KEYWORDS = [ "padding:", "display:", "S3=n8", "phpBB Debug", "getElementById", "innerHTML", "parseInt", "addEventListener", "console\.log", "checkCookieForTarget", "setAttribute", "getItem", "if \(", "else {", "JSON\.stringify", "onclick", ] WEBBOARD_KEYWORDS = [ "คุณกำลังใช้งานแบบปิดการใช้ Javascript", "Longdo Dictionary", "นโยบายการคุ้มครองข้อมูลส่วนบุคคล", "เงื่อนไขการให้บริการเว็บไซต์", "นโยบายความปลอดภัย", "นโยบายเว็บไซต์และการปฏิเสธความรับผิด", "คุณอาจจะยังไม่ได้เข้าสู่ระบบหรือยังไม่ได้ลงทะเบียน", "คุณไม่ได้เข้าสู่ระบบหรือคุณไม่มีสิทธิ์เข้าหน้านี้", ] PORN_KEYWORDS += [" ".join(list(kw)) for kw in PORN_KEYWORDS] GAMBLE_KEYWORDS += [" ".join(list(kw)) for kw in GAMBLE_KEYWORDS] SPAM_MOVIE_KEYWORDS += [" ".join(list(kw)) for kw in SPAM_MOVIE_KEYWORDS] DOCUMENT_REMOVAL_KEYWORDS = ( PORN_KEYWORDS + GAMBLE_KEYWORDS + SPAM_MOVIE_KEYWORDS + SPAM_LIKE_KEYWORDS + CODE_KEYWORDS + WEBBOARD_KEYWORDS ) PARTIAL_REMOVAL_KEYWORDS = [ "Posted on", "Posted by", "Posted by:", "Posted By:", "สมาชิกหมายเลข [0-9,]+", "อ่าน [0-9,]+ ครั้ง", "เปิดดู [0-9,]+ ครั้ง", "ดู [0-9,]+ ครั้ง", "คะแนนสะสม: [0-9,]+ แต้ม", "ความคิดเห็น: [0-9,]+", "[0-9,]+ บุคคลทั่วไป กำลังดูบอร์ดนี้", "หน้าที่แล้ว ต่อไป", "ความคิดเห็นที่ [0-9,]+", "[0-9,]+ สมาชิก และ [0-9,]+ บุคคลทั่วไป", "กำลังดูหัวข้อนี้", "เข้าสู่ระบบด้วยชื่อผู้ใช้", "แสดงกระทู้จาก:", "กระทู้: [0-9,]+", "เว็บไซต์เรามีการใช้คุกกี้และเก็บข้อมูลผู้ใช้งาน โปรดศึกษาและยอมรับ นโยบายคุ้มครองข้อมูลส่วนบุคคล ก่อนใช้งาน", "Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use\.", "Previous\t\nNext\nLeave a Reply Cancel reply\nYou must be logged in to post a comment.\nSearch for:\nFeatured Post\n", "Click to read more\nYou must be logged in to view or write comments\.", "[0-9,]+ Views", "Skip to content", "Last Modified Posts", "Last Updated:", "\(อ่าน [0-9,]+ ครั้ง\)", "Recent Comments", "«.*?»", "< --แสดงทั้งหมด-- >", "นโยบายความเป็นส่วนตัว", "เงื่อนไขการใช้เว็บไซต์", "ตั้งค่าคุกกี้", "ท่านยอมรับให้เว็บไซต์นี้จัดเก็บคุกกี้เพื่อประสบการณ์การใช้งานเว็บไซต์ที่ดียิ่งขึ้น", "รวมถึงช่วยให้ท่านมีโอกาสได้รับข้อเสนอหรือเนื้อหาที่ตรงตามความสนใจของท่าน", "ท่านสามารถดู Privacy Notice ของเว็บไซต์เรา ได้ที่นี่", "You may be trying to access this site from a secured browser on the server. Please enable scripts and reload this page.", "เผยแพร่: \d\d [ก-๙]+ \d\d\d\d \d\d:\d\d น\.", "Last updated: \d\d [ก-๙]+\.[ก-๙]+\. \d\d\d\d \d\d:\d\d น\.", "Lorem ipsum dolor sit amet, consectetur adipiscing elit\.", "Search for:", "Save my name, email, and website in this browser for the next time I comment", "Your email address will not be published. Required fields are marked", "Leave a Reply Cancel reply", "((?:หน้าหลัก|เข้าสู่ระบบ|หน้าแรก) \|(?: [^\s]+(?:(?: \|)|$|\s))+)", "กลับหน้าแรก", "ติดต่อเรา", "Contact Us", "#\w+", "ติดต่อผู้ดูแลเว็บไซต์", "หากท่านพบว่ามีข้อมูลใดๆที่ละเมิดทรัพย์สินทางปัญญาปรากฏอยู่ในเว็บไซต์โปรดแจ้งให้ทราบ", "No related posts", "Posted in", "((?:Tags:|Tagged|Tag) (?:.{1,40}(?:,|\n|$))+)", "ตอบ:", "Sort by:", "All rights reserved", "ความยาวอย่างน้อย", "ระบบได้ดำเนินการส่ง OTP", "เป็นสมาชิกอยู่แล้ว\?", "We use cookies", "Cookie Settings", "Homeหน้าหลัก", "Home หน้าหลัก", "ข่าวสารล่าสุด", "ปัญหา การใช้งาน", "ปัญหาการใช้งาน" "ผู้เขียน", "หัวข้อ:", "\*\* พร้อมส่ง \*\*", ] TH_MONTHS = [ "มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม", "ม\.ค\.", "ก\.พ\.", "มี\.ค\.", "เม\.ย\.", "พ\.ค\.", "มิ\.ย\.", "ก\.ค\.", "ส\.ค\.", "ก\.ย\.", "ต\.ค\.", "พ\.ย\.", "ธ\.ค\.", ] CODE_SPECIAL_CHARACTERS = ["\{", "\+", "\}", "/", ":"] PARTIAL_REMOVAL_KEYWORDS = sorted_by_len(PARTIAL_REMOVAL_KEYWORDS) import re from pythainlp.util import countthai from typing import List, Dict from datetime import datetime def contains_document_removal_keywords(text: str) -> bool: """ Description : Check if an input document contains any document removal keywords. Input text : An input document. Output : True if the document contains the keywords. Otherwise, False """ pattern = "|".join(DOCUMENT_REMOVAL_KEYWORDS) return bool(re.search(pattern, text)) def check_ratio_bad_substring(text: str) -> bool: """ Description : Check if the ratio between number of keywords and length of a document is exceeds the threshold for each groups. Group #1 : Name of months in Thai including abbreviations. Group #2 : Special char that usually found in the code section. Group #3 : Space. Group #4 : Commar. Note : Thresholds of each group are from the experiment on oscar. Input text : An input document. Output : True if a ratio of at least 1 group is above . Otherwise, False """ n = len(text) if len(re.findall("|".join(TH_MONTHS), text)) / n > 0.015: return True if len(re.findall("|".join(CODE_SPECIAL_CHARACTERS), text)) / n > 0.075: return True if len(re.findall(" ", text)) / n > 0.13: return True if len(re.findall(",", text)) / n > 0.05: return True return False def remove_partial_keywords(text: str) -> str: """ Description : Remove partial removal keywords from the document. Input text : An input document. Output : A document after removed keywords. """ return re.sub("|".join(PARTIAL_REMOVAL_KEYWORDS), "", text) def clean_oscar_text(text: str) -> str: """ Description : Clean an input document by these steps 1. Remove the whole document if 1.1. Contains any document removal keywords (ex. porn, gamble) 1.2. Contains too much TH months, code character, space and commar. 1.3. The percent of thai characters is less than 50%. 2. Remove partial removal keywords. Input text : An input document. Output : A clean document ("" if the whole document should be removed). """ if ( len(text) == 0 or contains_document_removal_keywords(text) or check_ratio_bad_substring(text) or countthai(text) < 50 ): return "" text = remove_partial_keywords(text).strip() return text def clean_dataset(dataset: List[Dict[str, str]]) -> List[Dict[str, str]]: """ Description : Call function clean_text to process the whole dataset. Input text : An input dataset having each element as a document in the dataset. Output : A clean dataset. """ for i, data_point in enumerate(dataset): cleaned_text = clean_text(data_point["text"]) if cleaned_text != dataset[i]["text"]: dataset[i]["text"] = cleaned_text dataset[i]["updated_date"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S") return [data_point for data_point in dataset if data_point["text"] != ""]