Groovyで文字列を置換する

正規表現にマッチした部分を固定の文字列に置換する

文字列のうち最初にマッチした1つだけを置換するなら、String#replaceFirstを使う。
マッチした全てを置換するなら、String#replaceAllを使う

ソース
ai = "あいあいあい"
println "置換前:" + ai
println "置換後  :" + ai.replaceFirst(/あい/,"愛")

println "置換しても元の文字列には影響はにない" + ai

println ""
println "置換後  :" + ai.replaceAll(/あい/,"愛")


println ""
test="abcdefg"
println "置換前:" + test
println "置換後 :" + test.tr("acg","ACG")


println ""
println "置換前:" + ai
println "置換後:" + ai.tr("い","お")


println ""
println "置換前:" + ai
println "置換後:" + ai.tr("あい","愛")
実行結果
[D:\workspace\groovy_SandBox]groovy Q052_文字列の一部を置換する.groovy
置換前:あいあいあい
置換後  :愛あいあい
置換しても元の文字列には影響はにないあいあいあい

置換後  :愛愛愛

置換前:abcdefg
置換後 :AbCdefG

置換前:あいあいあい
置換後:あおあおあお

置換前:あいあいあい
置換後:愛愛愛愛愛愛
疑問

Rubyと同じようにtr()もある。
tr()で、"あい"を"愛"のように、マルチバイトを複数使ってと変換するreplaceAllとは違う結果になる。
Rubyと同じようにGroovyのtr()もマルチバイト文字には対応してないのか?それともバグか?



正規表現にマッチした部分を式の実行結果の文字列に置換する

固定文字列ではなく、式の実行結果の文字列に置換するなら、Clousure(クロージャー)を
使う。

ソース
if( org.codehaus.groovy.runtime.InvokerHelper.getVersion() < "1.7.7" ) {
    println "Groovy 1.7.7以上が必要です"
    return
}
queue = ["愛","哀","相"]
i=0
println "あいあいあい".replaceFirst(/あい/) { queue[i++] }
i=0
println "あいあいあい".replaceAll(/あい/) { queue[i++] }

queue = ["愛","哀","相"]
println "あいあいあい".replaceFirst(/あい/) { queue.pop() }
queue = ["愛","哀","相"]
println "あいあいあい".replaceAll(/あい/) { queue.pop() }

println ""
println "FrontPage".replaceFirst(/(.)([A-Z])/){it[1] + " " + it[2]}
println "MyToDo".replaceAll(/(.)([A-Z])/){it[1] + " " + it[2]}
実行結果
[D:\workspace\groovy_SandBox]groovy Q052_文字列の一部を置換する2.groovy
愛あいあい
愛哀相
相あいあい
相哀愛


Front Page
My To Do
補足

       1.7.7以降

       1.0以降

replaceFirstとreplaceAllとでずいぶんサポートした時期に差があるんだな。



Rubyのshift()メソッドの代わりはpop()で。
Groovy イン・アクション p90より

リストは①のようにプッシュ(push)やポップ(pop)といった一般的なスタック操作によって
スタックのように扱うことができます。プッシュ操作は、リストの左シフト演算子(<<)に
割り当てられています。


iを使った配列の操作でもいいが、Groovyぽっく各とすると後者のpopになるのだろうか。
でも、スタックなので、一度空になってしまうので、リストを2度定義する必要がある。
それがなんかいやだな。

"FrontPage".replaceFirst(/(.)([A-Z])/){it[1] + " " + it[2]}

itの中身は[tP, t, P]のようになる。
そのため、置換後の文字列を使うには、it[1],it[2]を使う。



範囲を指定して置換する

ソース
result = ['N','a','m','a','z','u']
println result
result[1..1] = 'u'

println result


result = "Numa-"
result[0,1] = 'k'
println result
実行結果
[D:\workspace\groovy_SandBox]groovy Q052_文字列の一部を置換する3.groovy
[N, a, m, a, z, u]
[N, u, m, a, z, u]

Caught: groovy.lang.MissingMethodException: No signature of method: java.lang.String.putAt() is applicable for argument types: (groovy.lang.IntRange, java.lang.String) values: [0..1, k]
Possible solutions: putAt(java.lang.String, java.lang.Object), getAt(groovy.lang.IntRange), getAt(groovy.lang.IntRange), getAt(java.lang.String), getAt(groovy.lang.Range), getAt(groovy.lang.Range)

補足

result[0..1] = 'k' に変更してもダメだった。。

result = "Numa-"
result[0..1] = 'k'
println result
Caught: groovy.lang.MissingMethodException: No signature of method: java.lang.String.putAt() is applicable for argument types: (java.util.ArrayList, java.lang.String) values: [[0, 1], k]
Possible solutions: putAt(java.lang.String, java.lang.Object), getAt(java.lang.String), getAt(groovy.lang.EmptyRange), getAt(groovy.lang.EmptyRange), getAt(groovy.lang.Range), getAt(groovy.lang.Range)


Rubyだとが出来るようだが、Groovyではダメのようだ。

result = "Numa-"
result[0..1] = 'k'
p result #=> "Kuma-"


String自身は配列じゃないからかな?





実行環境

replaceFirst(String regex, Closure closure)が1.7.7以降のため、Groovyのバージョンがいつもと違う。









Groovyの詳細についてはJavadocと以下の書籍を参考にしている。




Dierk Konig、Andrew Glover、Paul King、、Guillaume Laforge、Jon Skeet、杉浦 孝、櫻井 正樹、須江 信洋、関谷 和愛、佐野 徹郎、寺沢 尚史

出品者からお求めいただけます。
価格は記載時点のものです。購入前にAmazonでご確認ください。




問題自体は第2版のもの。rubyと似てる部分も多いので、ヒントにもなる。
写経でもいいが自分で考えるために他言語の例をGroovyで置き換えてる。




青木 峰郎、後藤 裕蔵、高橋 征義、まつもと ゆきひろ

価格: ¥ 2,940
価格は記載時点のものです。購入前にAmazonでご確認ください。




Groovyイン・アクションを読むならあった方が便利かな。

Rubyレシピブックは「ほんたった」で立ててる