#概要
切れ目の存在する2つの文字列において、切れ目の位置がどの程度一致しているかを計算するプログラムを書きました。
「〇〇で歌ってみた」というジャンルの替え歌において、本来の歌詞の文節の切れ目と替え歌歌詞の単語の切れ目がどの程度一致しているかを調べるために作りました。
#背景
「〇〇で歌ってみた」は特定カテゴリの名詞だけで本来の歌詞の発音を再現するように歌われた替え歌のことです。下図は童謡『ふるさと』の歌詞を駅名に置き換えた「〇〇で歌ってみた」の例です。
「〇〇で歌ってみた」では替え歌歌詞の単語の切れ目と本来の歌詞の文節の切れ目がどちらかというと一致するように作られる傾向があります。理由は定かではありませんが、一つにはそのほうが歌いやすいからという理由が考えられます。いくつかの替え歌において、どの程度一致しているかを調べたくなったので、2つの文章の文節一致率を評価するプログラムを書いてみることにしました。
#解きたい問題
文字列Aと文字列Bが与えられて、2つの文節一致率を求めることが目標です。
##入力
簡単のため、2つの文字列のモウラ数は同じとします。また発音(読み方)と文節(単語)の切れ目は既知とします。発音はカタカナで、文節の切れ目はスラッシュで表記することとします。例えば下記のような文字列を入力として想定します。
- 文字列A(替え歌歌詞):カモメ/カモメ/カグー/ナガノゴリ/サイ/クイ/ツミ/ラット/ウシ/ロバ/ヒョウ/メナダ/アビ
- 文字列B(本来の歌詞):カゴメ/カゴメ/カゴノ/ナカノ/トリワ/イツ/イツ/デアッタ/ウシロノ/ショウメン/ダアレ
##出力
文字列Aと文字列Bの文節一致率を出力します。
文節一致率は文字列Aの文節の切れ目のうち、文字列Bの文節の切れ目と同じ位置にあるものの割合と定義します。同じ位置であるかどうかは、その文節の切れ目の直前までに存在する文字列のモウラ数で判断します。また文字列の最後は文節の切れ目とはみなしません。例えば先に示したカゴメの例で、文字列Bのうち一致している切れ目をダブルクオテーションで示すと以下になります。
- 文字列A(替え歌歌詞):カモメ"/"カモメ"/"カグー"/"ナガノゴリ/サイ/クイ/ツミ/ラット"/"ウシ/ロバ"/"ヒョウ/メナダ/アビ
- 文字列B(本来の歌詞):カゴメ/カゴメ/カゴノ/ナカノ/トリワ/イツ/イツ/デアッタ/ウシロノ/ショウメン/ダアレ
文字列Bの文節の切れ目の数(=スラッシュの数)は12で、そのうち文字列Aの文節の切れ目と一致しているものは、5個です。文字数ではなくモウラ数(例えばヒョは2文字ですが、1モウラです)で数えることに注意してください。
#環境
macOS Catalina 10.15.7
python 3.8.0
#コード
与えられた文字列をモウラの単位に分解してから、スラッシュの位置をカウントします。
import re
#各条件を正規表現で表す
c1 = '[ウクスツヌフムユルグズヅブプヴ][ヮァィェォ]' #ウ段+「ヮ/ァ/ィ/ェ/ォ」
c2 = '[イキシシニヒミリギジヂビピ][ャュェョ]' #イ段(「イ」を除く)+「ャ/ュ/ェ/ョ」
c3 = '[テデ][ャィュョ]' #「テ/デ」+「ャ/ィ/ュ/ョ」
c4 = '[ァ-ヴー]' #カタカナ1文字(長音含む)
cond = '('+c1+'|'+c2+'|'+c3+'|'+c4+')'
re_mora = re.compile(cond)
#カタカナ文字列をモウラ単位に分割したリストを返す
def mora_wakachi(kana_text):
return re_mora.findall(kana_text)
def phrase_partition_concordance(text1, text2):
partition = "/"
#文字列を区切り文字でスプリット
kana_list1 = text1.split(partition)
kana_list2 = text2.split(partition)
#各要素をモウラに分割
kana_list1 = [mora_wakachi(k) for k in kana_list1]
kana_list2 = [mora_wakachi(k) for k in kana_list2]
#text1の文節位置を取得
partition_position1 = [0]
for k in kana_list1:
pos = partition_position1[-1] + len(k)
partition_position1.append(pos)
#最初と最後は文節位置から除く
partition_position1 = partition_position1[1:-1]
#text2の文節位置を取得
partition_position2 = [0]
for k in kana_list2:
pos = partition_position2[-1] + len(k)
partition_position2.append(pos)
#最初と最後は文節位置から除く
partition_position2 = partition_position2[1:-1]
#text1の文節位置がtext2の文節位置に含まれるかチェック
same_pos_num = 0
for p in partition_position1:
if p in partition_position2:
same_pos_num += 1
#text1の文節の切れ目の数
partition_num = len(partition_position1)
return same_pos_num / partition_num
text1 = "カモメ/カモメ/カグー/ナガノゴリ/サイ/クイ/ツミ/ラット/ウシ/ロバ/ヒョウ/メナダ/アビ"
text2 = "カゴメ/カゴメ/カゴノ/ナカノ/トリワ/イツ/イツ/デアッタ/ウシロノ/ショウメン/ダアレ"
print(phrase_partition_concordance(text1,text2))