読者です 読者をやめる 読者になる 読者になる

Scala で文字検索、置換

Scala

文字列とか正規表現とか、よく分からんけれど使ってみようぜ的な、ね。

何にも考えない置換。

println( "abc_abc".replaceAll( "abc", "123" ) );
// "123_123"


String.replaceAll の第一引数は正規表現を受け取るようになってます。

println( "abc_abc".replaceAll( "[a-z]+", "123" ) );
// "123_123"


検索だけならこれがお手軽。

println( "abc_abc".contains( "abc" ) );
// true


でもそれだけじゃなくて、検索の結果見つかった位置も知りたいときはとりあえずコレかな。

println( "abc_abc".indexOfSlice( "abc", 0 ) );
// 0
println( "abc_abc".indexOfSlice( "abc", 1 ) );
// 4


ただ、indexOfSlice の第一引数は正規表現ではないので用途は限定されそうです。

println( "abc_abc".indexOfSlice( "[a-z]+", 0 ) );
// - 1


さて、もっと細かくやりたいときは 「.r」を使いませう。

val r = "([a-z]+)".r; // .r をつけると Regex オブジェクトができる。
r.findAllIn( "abc_def" ).matchData.foreach(
  m => println( m.group( 1 ) )
);
// "abc"
// "def"


↑文字列 "abc_def" の中で正規表現 r にマッチする部分は 1 箇所とは限らないので、それぞれについて foreach で m => println( ... ) してます。m.group( 1 ) は、正規表現中で "()" 指定したモノの 1 番にマッチした部分文字列です。

...つまりこういうコト。

val r = "([a-z]+)_([0-9]+)".r;
r.findAllIn( "abc_123, def_456" ).matchData.foreach(
  m => println( m.group( 1 ) + ", " + m.group( 2 ) )
);
// "abc, 123"
// "def, 456"

ところで m.group( index ) の index に 0 を渡すとマッチした部分そのものを取得できます。また m.start, m.end で元文字列のどの位置でマッチしたのかを知ることが出来ます。

val r = "([a-z]+)_([0-9]+)".r;
r.findAllIn( "abc_123, def_456" ).matchData.foreach(
  m => println( m.group( 0 ) + " ( " + m.start + " ~ " + m.end + " )" )
);
// "abc_123 ( 0 ~ 7 )"
// "def_456 ( 9 ~ 16 )"


■■ 追記 ■■
大事なのを書き忘れてました。Scala なら match *1使わないとね!

val r = "([a-z]+)([0-9]+)".r;
println( "abc123" match {
  case r( a, n ) => a + ", " + n;
  case _         => ""
} );
// "abc, 123"

*1:しかし "123".match { ... } でコンパイル通らないのは何故なんだぜ?