Last active
March 10, 2024 11:38
-
-
Save litagin02/5eb8a6d02587bcb7b71518907b45fedb to your computer and use it in GitHub Desktop.
笑い声・感動詞を文字列から識別するやつ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import re | |
import jaconv | |
# お好きな日本語文章正規化をimport, jaconv.normalizeとかでいいかも | |
from text import text_normalize | |
import regex | |
import pyopenjtalk | |
# 「ー」と「っ」を取り除いた文章に対するひらがなの笑い声の正規表現 | |
warai_pattern = ( | |
r"(" | |
# 「は」行を最後に含む系統 | |
+ r"あ+は+|い+ひ+|う+(は+|ひ+|ふ+|へ+|ほ+)|え+へ+|お+ほ+|" | |
+ r"かは+|きひ+|く(は+|ひ+|ふ+|へ+|ほ+)|けへ+|" | |
+ r"がは+|ぎひ+|ぐ(は+|ひ+|ふ+|へ+|ほ+)|げへ+|" | |
+ r"きゃは+|ぎゃは+|" | |
+ r"たは+|てへ+|" | |
+ r"なは+|に(は+|ひ+|ふ+|へ+|ほ+)|ぬ(は+|ひ+|ふ+|へ+|ほ+)|" | |
+ r"にゃは+|にゅふ+|にょほ+|" | |
+ r"ふ+(は+|ひ+|ふ+|へ+|ほ+)|" | |
+ r"ぶ+(は+|ひ+|ふ+|へ+|ほ+)|" | |
+ r"ぷ+(は+|ひ+|ふ+|へ+|ほ+)|" | |
+ r"(む|も)(は+|ひ+|ふ+|へ+|ほ+)|" | |
+ r"わ+は+|うぃひ+|うぇへ+|うぉほ+|" | |
+ r"ん(は+|ひ+|ふ+|へ+|ほ+)|" | |
# 「ひゃ」で終わる系統(叫び声もある) | |
+ r"あ(ひゃ)+|う(ひゃ)+|う(ひょ)+|" | |
# 「し」で終わる系統 | |
+ r"(い|き|に)し+|" | |
# 「ん」で終わる系統(自慢げや感心の感嘆詞の可能性もある) | |
+ r"ふ{2,}ん|へ{2,}ん|ほ{2,}ん|" | |
# 2回以上の繰り返し | |
+ r"か{2,}|く{2,}|け{2,}|は{2,}|ひ{2,}|ふ{2,}|へ{2,}|ほ{2,}|ぷ{2,}|" | |
# 擬態語 | |
+ r"くす|けら|げら|にこ|にや|にた|にか|にま|" | |
+ r"てへ+|" | |
+ r"にやり)+" | |
) | |
# 母音撥音促音等のパターン | |
basis = r"[あいうえおやゆよわんぁぃぅぇぉゃゅょゎーっ]" | |
# (母音 +)◯◯(+ 母音)で感嘆詞とみなせるパターン | |
single_nv_pattern = ( | |
# フィラー | |
r"あ[ー]*|あの[うおー]*|え[ーっ]*と?|その[おー]*|ま[あー]*|う[ー]*ん?|" | |
# それ以外の単体の感嘆詞や口語表現 | |
+ r"ちぇ|くそ|(やれ){2,}|すご|ちくしょ|やば|まじ(か|で)?|あれ+|でし|" | |
+ r"おっ?け|あっぱれ|おっ?す|うぃ?っ?す|しまった|よくも?|" | |
) | |
# ひらがな(「ー」「っ」含む)に対する非言語音声・感嘆詞の正規表現 | |
nv_pattern = ( | |
r"(" | |
# 母音等の2回以上の繰り返しの場合(「うおわー」「いやぁ」「うん」等) | |
+ rf"{basis}{{2,}}|" | |
# 母音等以外が先頭・間に来る場合(「やったー」「げげ」「ぎょわあーーっ」「うみゃみゃーん」等) | |
+ rf"{basis}*(" | |
+ r"き+|く+|が+|ぎ+|ぐ+|げ+|し+|そ+|た+|て+|と+|な+|に+|ぬ+|は+|ひ+|ふ+|へ+|ほ+|む+|" | |
+ r"ち?(ちゃ)+|ち?(ちゅ)+|ち?(ちょ)+|に?(にゃ)+|み?(みゃ)+|(ひゃ)+|(ひゅ)+|(ひょ)+|(しゃ)+|(しゅ)+|(しょ)+|" | |
+ rf"{single_nv_pattern}" | |
+ rf"){basis}*|" | |
# 「ら」「りゃ」が間に入る場合(「ありゃ」「おらー」「てりゃりゃー」等) | |
+ rf"[あいうおこてとんぁぃぅぇぉゃゅょゎーっ]+(ら|りゃ)+{basis}*" | |
+ r")+" | |
) | |
def is_laughing(text: str) -> bool: | |
text = text_normalize(text) | |
# 句読点やスペース、ハイフンを削除(「ー」「っ」は残す) | |
text = re.sub("[" + re.escape("。、!?,.'- ") + "]", "", text) | |
# wの繰り返しの場合はTrueを返す(書き起こし結果がたまに「www」となる) | |
if re.fullmatch(r"(w|W)+", text): | |
return True | |
# 漢字が含まれている場合はFalseを返す | |
if regex.search(r"\p{Script=Han}", text): | |
return False | |
# ひらがな、カタカナ以外があったらFalseを返す | |
if not re.fullmatch(r"[\u3040-\u309F\u30A0-\u30FF]+", text): | |
return False | |
# カタカナをひらがなに変換 | |
text = jaconv.kata2hira(text) | |
# 「ー」と「っ」を取り除く | |
text = re.sub("[っー]", "", text) | |
# 全体がパターンにマッチするかどうかを判定 | |
return bool(re.fullmatch(warai_pattern, text)) | |
def is_kandoushi(text: str) -> bool: | |
result = pyopenjtalk.run_frontend(text) | |
for r in result: | |
if r["pos"] not in ["感動詞", "フィラー", "記号"]: | |
return False | |
return True | |
def is_nv(text: str) -> bool: | |
text = text_normalize(text) | |
if text == "": | |
return False | |
# 解析で感動詞、フィラー、記号のみからなればTrueを返す | |
if is_kandoushi(text): | |
return True | |
# 漢字が含まれている場合はFalseを返す | |
if regex.search(r"\p{Script=Han}", text): | |
return False | |
# 句読点やスペース、ハイフンを削除(「ー」「っ」は残す) | |
text = re.sub("[" + re.escape("。、!?,.'- ") + "]", "", text) | |
# ひらがな、カタカナ以外があったらFalseを返す | |
if not re.fullmatch(r"[\u3040-\u309F\u30A0-\u30FF]+", text): | |
return False | |
if text == "": | |
return False | |
# カタカナをひらがなに変換 | |
text = jaconv.kata2hira(text) | |
# フィラーパターンにマッチするかどうかを判定 | |
if bool(re.fullmatch(single_nv_pattern, text)): | |
return True | |
# nvパターンにマッチするかどうかを判定 | |
if not bool(re.fullmatch(nv_pattern, text)): | |
return False | |
# 特定の単語が含まれている場合はFalseを返す | |
# 主に上のパターンでの1文字部分の繰り返しで意味のある単語ができてしまう場合に使用 | |
exclude_words = [ | |
"あなた", | |
"あんた", | |
"やがて", | |
"たとえ", | |
"とはいえ", | |
"よくない", | |
"なんとなく", | |
"そして", | |
"そうして", | |
"したい", | |
"いいよ", | |
] # 適宜追加 | |
if any(word in text for word in exclude_words): | |
return False | |
return True | |
def is_kana_only(text: str) -> bool: | |
text = text_normalize(text) | |
# 削除したい文字を削除 | |
text = re.sub("[" + re.escape("。、!?,.'- ") + "]", "", text) | |
# ひらがな、カタカナのみからなるかどうかを判定 | |
return bool(re.fullmatch(r"[\u3040-\u309F\u30A0-\u30FF]+", text)) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment