LoginSignup
0
1

正規表現の先読みを使ってテキストを文区切りで改行する

Posted at

前提

文章を句点 (。) で改行して、1行に1文だけ保持されているような文字列を得たいです。

たとえば以下の文章があるとき、

 叢の中からは、暫く返辞が無かった。しのび泣きかと思われる微かな声が時々洩れるばかりである。
ややあって、低い声が答えた。「如何にも自分は隴西の李徴である」と。

以下の出力を得たいです。

 叢の中からは、暫く返辞が無かった。
しのび泣きかと思われる微かな声が時々洩れるばかりである。
ややあって、低い声が答えた。
「如何にも自分は隴西の李徴である」と。

方法

正規表現の先読みアサーション (Lookahead assertion, たんに先読みとも) を使います。
先読みアサーションとは、「後ろに x という表現が続くような(または続かないような) exp」にマッチさせる表現のことです。

種類 記述例 マッチ例
ポジティブアサーション /exp(?=ress)/g 'express explosion experiment'
ではじめの exp だけマッチ
ネガティブアサーション /exp(?!ress)/g 'express explosion experiment'
で後ろ2つの exp だけマッチ

当然後読みアサーション (Lookbehind assertion) というものもありますが、今回は使わないので割愛します。

環境

Bun 1.1.3
今回はJSでコードを書きますが、正規表現なのでたいていどこでも同じように実装可能です。

コード例

失敗例

index.ts
const text = ' 叢の中からは、暫く返辞が無かった。しのび泣きかと思われる微かな声が時々洩れるばかりである。\nややあって、低い声が答えた。「如何にも自分は隴西の李徴である」と。';

console.log(text.replace(/。/g, '\n'));

実行結果

 叢の中からは、暫く返辞が無かった。
しのび泣きかと思われる微かな声が時々洩れるばかりである。

ややあって、低い声が答えた。
「如何にも自分は隴西の李徴である」と。

余計な改行が入ってしまいます。

先読みアサーションを使わないコード

index.ts
const text = ' 叢の中からは、暫く返辞が無かった。しのび泣きかと思われる微かな声が時々洩れるばかりである。\nややあって、低い声が答えた。「如何にも自分は隴西の李徴である」と。';

console.log(text.replace(/。([^\n$])/g, '\n$1'));

実行結果

 叢の中からは、暫く返辞が無かった。
しのび泣きかと思われる微かな声が時々洩れるばかりである。
ややあって、低い声が答えた。
「如何にも自分は隴西の李徴である」と。

句点のあとが改行 \n ないし終端 $ ではない場合だけ次の文字を含めてマッチし、その句点の次の文字を $1 で後方参照することで、文のあとに適切に改行を挿入しています。
期待した結果が得られましたが、読みづらいしなんだか冗長な感じがしてしまいます1

先読みアサーションを使うコード

index.ts
const text = ' 叢の中からは、暫く返辞が無かった。しのび泣きかと思われる微かな声が時々洩れるばかりである。\nややあって、低い声が答えた。「如何にも自分は隴西の李徴である」と。';

console.log(text.replace(/。(?!\n|$)/g, '\n'));

実行結果

 叢の中からは、暫く返辞が無かった。
しのび泣きかと思われる微かな声が時々洩れるばかりである。
ややあって、低い声が答えた。
「如何にも自分は隴西の李徴である」と。

(?!...) を使うことで、改行 \n ないし終端 $ に続かない句点だけをマッチし、改行を挿入することができました。
コードもスッキリと記述できています。

雑感

基本的な正規表現は一通り勉強したつもりでしたが、やはり具体的なケースに適用することで、使いどころ込みで理解できるなあと実感しました。

  1. ちなみにMDNには、「キャプチャグループはパフォーマンス上の損失があります。」と書かれています。JavaScript 以外の場合がどうなのかはわかりません。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1