Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

Excerpt
hiddentrue

Groovy supports regular expressions natively using the ~"pattern" expression, which creates a compiled Java Pattern object from the given pattern string. Groovy also supports the =~ (create Matcher) and ==~ (returns boolean, whether String matches the pattern) operators.

For matchers having groups, matcher[index] is either a matched String or a List of matched group Strings.

Groovyはネイティブで ~"パターン" 表記を使用した正規表現をサポートします。それは、与えられたパターン文字列からコンパイルされた Java Pattern オブジェクトを生成します。また、Groovyは =~ 演算子(Matcherを生成)と ==~ 演算子(Stringとそのパターンがマッチするかどうかのboolean値を返す)もサポートします。

Matcherオブジェクトはグループを持つことがあるため、matcher[index]がマッチした文字列もしくはマッチしたグループの文字列リストとなります。

Code Block
import java.util.regex.Matcher
import java.util.regex.Pattern


// ~ はStringからPatternを生成します。
def pattern = ~/foo/
assert pattern instanceof Pattern
assert pattern.matcher("foo").matches() // TRUEを返します。
assert pattern.matcher("foobar").matches() // FALSEを返します。matches()はString全体にマッチしなければならないためです。
// =~ はMatcherオブジェクトを生成しますが、boolean値を要求するコンテキストでは、少なくとも1度のマッチがある場合"true"、
// そうでない場合"false"となります。
assert "cheesecheese" =~ "cheese"
assert "cheesecheese" =~ /cheese/
assert "cheese" == /cheese/ /* これは共に文字列として評価される*/
assert ! ("cheese" =~ /ham/)

// ==~ は、Stringがパターンにマッチするかどうかをテストします。
assert "2009" ==~ /\d+/ // TRUEを返します。
assert "holla" ==~ /\d+/ // FALSEを返します。

// Matcherオブジェクトを作成しましょう。
def matcher = "cheesecheese" =~ /cheese/
assert matcher instanceof Matcher

// 置換をいくつか行いましょう
def cheese = ("cheesecheese" =~ /cheese/).replaceFirst("nice")
assert cheese == "nicecheese"
assert "color" == "colour".replaceFirst(/ou/, "o")

def cheese = ("cheesecheese" =~ /cheese/).replaceAll("nice")
assert cheese == "nicenice"


// グループを使う簡単な例
// グループを含むパターンをマッチさせることができます。まずMatcherオブジェクトを生成し、
// Java API を使用するか、あるいはもっと簡単に =~ 演算子を使用します。そして、index値を使って
// Matcherオブジェクトからマッチを参照することができます。matcher[0]は文字列中で正規表現にマッチした
// 最初のマッチを表すリストを返します。そのリストの最初の要素は正規表現全体にマッチした文字列で、
// 残りの要素はそれぞれのグループにマッチした文字列です。
// 以下がその動作です。
def m = "foobarfoo" =~ /o(b.*r)f/
assert m[0] == ["obarf", "bar"]
assert m[0][1] == "bar"

// Matcherはリストではありませんが、Groovy 1.6 からリストのようにindex値を使うことができます。
// これには、index値としてコレクションを使うことも含みます。

def matcher = string =~ "e+"

assert "ee" == matcher[2]
assert ["ee", "e"] == matcher[2..3]
assert ["ee", "ee"] == matcher[0, 2]
assert ["ee", "e", "ee"] == matcher[0, 1..2]

matcher = "cheese please" =~ /([^e]+)e+/
assert ["se", "s"] == matcher[1]
assert [["se", "s"], [" ple", " pl"]] == matcher[1, 2]
assert [["se", "s"], [" ple", " pl"]] == matcher[1 .. 2]
assert [["chee", "ch"], [" ple", " pl"], ["ase", "as"]] == matcher[0, 2..3]
// Matcherはiterator()メソッドを定義しているため、例えばcollect()メソッド、
// each()メソッドなどを使うことができます。
matcher = "cheese please" =~ /([^e]+)e+/
matcher.each { println it }
matcher.reset()
assert matcher.collect { it }  ==
[["chee", "ch"], ["se", "s"], [" ple", " pl"], ["ase", "as"]]
// Groovy 1.6 でイテレータのセマンティクスが変更されました。
// 1.5では、それぞれのイテレーションはグループを無視して、常にマッチした全体の文字列を返していました。
// 1.6では、正規表現にグループが含まれていれば、イテレーションは上記のように文字列のリストを返します。

// there is also regular expression aware iterator grep() イテレータのgrep()メソッドでも正規表現を使います。
assert ["foo", "moo"] == ["foo", "bar", "moo"].grep(~/.*oo$/)
// which can be written also with findAll() method 同じことをfindAll()メソッドでも書くことができます。
assert ["foo", "moo"] == ["foo", "bar", "moo"].findAll { it ==~ /.*oo/ }

Excerpt
hiddentrue

Since a Matcher coerces to a boolean by calling its find method, the =~ operator is consistent with the simple use of Perl's =~ operator, when it appears as a predicate (in 'if', 'while', etc.). The "stricter-looking" ==~ operator requires an exact match of the whole subject string. It returns a Boolean, not a Matcher.

Regular expression support is imported from Java. Java's regular expression language and API is documented here.


Matcherは *find()*メソッドをコールすることで強制的にboolean値となるため、(if文、while文ほかの)条件節として現れたとき、 =~ 演算子はPerlの =~ 演算子の単純な使用法と同じ働きをします。
”より厳密に働くように見える” ==~ 演算子は、対象文字列全体との正確なマッチを要求します。Matcherではなく、Booleanを返します。

正規表現のサポートは、Javaから取り込まれています。Javaの正規表現言語とAPIはここにドキュメントされています。

Excerpt
hiddentrue

More Examples

他の例

Excerpt
hiddentrue

Goal: Capitalize words at the beginning of each line:


目的: 各行の始めにある単語の語頭を大文字にします:

Code Block
def before='''
apple
orange
y
banana
'''

def expected='''
Apple
Orange
Y
Banana
'''

assert expected == before.replaceAll(/(?m)^\w+/,
{ it[0].toUpperCase() + ((it.size() > 1) ? it[1..-1] : '') })

Excerpt
hiddentrue

Goal: Capitalize every word in a string:


目的: 文字列中の全ての単語の語頭を大文字にします:

Code Block
assert "It Is A Beautiful Day!" ==
("it is a beautiful day!".replaceAll(/\w+/,
{ it[0].toUpperCase() + ((it.size() > 1) ? it[1..-1] : '') }))

Excerpt
hiddentrue

Add .toLowerCase() to make the rest of the words lowercase


単語の残りの部分を小文字にするために.toLowerCase() を追加します。

Code Block
assert "It Is A Very Beautiful Day!" ==
("it is a VERY beautiful day!".replaceAll(/\w+/,
{ it[0].toUpperCase() + ((it.size() > 1) ? it[1..-1].toLowerCase() : '') }))

Excerpt
hiddentrue

Gotchas

つまづきやすいところ

Excerpt
hiddentrue

How to use backreferences with String.replaceAll()

GStrings do not work as you'd expect:


String.replaceAll() の後方参照の使い方では、GStringは期待通りに動作しません

Code Block
def replaced = "abc".replaceAll(/(a)(b)(c)/, "$1$3")

Excerpt
hiddentrue

Produces an error like the following:


これは次のようなエラーとなります。

... illegal string body character after dollar sign:

solution: either escape a literal dollar sign "\$5" or bracket the value expression "${5}" @ line ...

Excerpt
hiddentrue

Solution:

Use ' or / to delimit the replacement string:


解決法:

置換文字列を ' か / で括るようにします。

Code Block
def replaced = "abc".replaceAll(/(a)(b)(c)/, '$1$3')