01.7.10
日本語文を安全に分割する
! ? も含む)の位置で文単位に分割します。単純な text.split("。") と違い、正規表現 SENTENCE_END の先読みで「直後が閉じ括弧なら切らない」というルールを入れているので、「(本当に?)」の中の疑問符では分割されません。finditer で文末記号の位置を順に拾い、句点のない最後の「了解しました👍」も tail として取り出します。形態素解析や文ごとの感情分析に渡す前の、チャットログや議事録の整形に使います。直感 #
チャットの「今日は打ち合わせ!(本当に?)気を付けてね…。了解しました👍」を文に分けたいとき、text.split("。") では「!」で切れず、split("?") では括弧の中の「?」でも切れてしまいます。人が読むときの区切りは「文末記号の直後、ただし閉じ括弧が続くときは括弧の外まで」なので、そのルールを正規表現に写します。文末記号を見つけたら、そこまでを 1 文として切り出し、残りの先頭から次を探す。これを繰り返し、最後に記号のない残りがあればそれも 1 文として足します。
Python で分割する #
次のコードは文末記号と先読みを 1 本の正規表現にまとめ、split_sentences が文のリストを返します。サンプルには括弧内の疑問符、三点リーダ、句点のない末尾の文を混ぜています。
| |
実行結果の読み方 #
1 文目は「!」の直後が「(」なので切れ、2 文目は「(本当に?)」の「?」の直後が「)」なので切れず、「…。」の「。」までが 1 文になります。3 文目は句点がないため tail として追加された文です。括弧の中で文が終わる「(本当に?)」を 1 文として独立させたい場合は、先読みの除外文字から「)」を外せば挙動が変わります。
使いどころと落とし穴 #
括弧内の疑問符で分割したくないケースは今のルールで対応できますが、逆に「」の中の「。」でも切りたい場合は、SENTENCE_END の先読みにある除外文字クラスから「」」を外して調整します。Slack などで見かける句点も改行もない長文には、文末記号が 1 つも見つからず全体が 1 文になるので、20〜30 文字ごとに強制分割するフォールバックを split_sentences の後ろに用意すると下流の処理が安定します。高い精度が求められる場合は、日本語に対応した文分割モデル(spaCy と GiNZA の senter、ja_sentence_segmenter など)を選定し、このルールベース分割は依存の少ない簡易版として併用するのがおすすめです。