1. 概要

このチュートリアルでは、 Groovy のいくつかのタイプの文字列を詳しく見ていきます。これには、一重引用符、二重引用符、三重引用符、スラッシュ文字列が含まれます。

また、特殊文字、複数行、正規表現、エスケープ、および変数補間に対するGroovyの文字列サポートについても説明します。

2. 強化java.lang.String

GroovyはJavaに基づいているため、連結、文字列API、文字列定数プールの固有の利点など、Javaの文字列機能をすべて備えていることから始めるとよいでしょう。そのための。

まず、Groovyがこれらの基本のいくつかをどのように拡張するかを見てみましょう。

2.1. 文字列の連結

文字列の連結は、2つの文字列の単なる組み合わせです。

def first = 'first'
def second = "second"        
def concatenation = first + second
assertEquals('firstsecond', concatenation)

Groovyがこれに基づいて構築されているのは、他のいくつかの文字列タイプです。これについては、後で説明します。 各タイプを交換可能に連結できることに注意してください。

2.2. 文字列補間

現在、Javaは printf を介して非常に基本的なテンプレートを提供していますが、Groovyはさらに深く、文字列補間、変数を使用して文字列をテンプレート化するプロセスを提供しています。

def name = "Kacper"
def result = "Hello ${name}!"
assertEquals("Hello Kacper!", result.toString())

Groovyはすべての文字列タイプの連結をサポートしていますが、特定のタイプの補間のみを提供します。

2.3. GString

しかし、この例には小さなしわが隠されています– なぜtoString()を呼び出すのですか?

実際、 result は、たとえそのように見えても、Stringタイプではありません。

Stringクラスはfinalであるため、補間をサポートするGroovyの文字列クラスGStringはそれをサブクラス化しません。 言い換えると、Groovyがこの拡張機能を提供するために、には独自の文字列クラスGStringがあり、Stringから拡張することはできません。

簡単に言えば、次のようになります。

assertEquals("Hello Kacper!", result)

これにより、 assertEquals(Object、Object)、が呼び出され、次のようになります。

java.lang.AssertionError: expected: java.lang.String<Hello Kacper!>
  but was: org.codehaus.groovy.runtime.GStringImpl<Hello Kacper!>
Expected :java.lang.String<Hello Kacper!> 
Actual   :org.codehaus.groovy.runtime.GStringImpl<Hello Kacper!>

3. シングルクォート文字列

おそらく、Groovyで最も単純な文字列は、一重引用符で囲まれた文字列です。

def example = 'Hello world'

内部的には、これらは単なる古いJava Strings であり、文字列内に引用符を含める必要がある場合に便利です

それ以外の:

def hardToRead = "Kacper loves \"Lord of the Rings\""

ある文字列を別の文字列と簡単に連結できます。

def easyToRead = 'Kacper loves "Lord of the Rings"'

このように引用符の種類を交換できるため、引用符をエスケープする必要が少なくなります。

4. トリプルシングル引用文字列

トリプルシングルクォート文字列は、複数行のコンテンツを定義する場合に役立ちます。

たとえば、文字列として表すJSONがあるとします。

{
    "name": "John",
    "age": 20,
    "birthDate": null
}

これを表すために、連結や明示的な改行文字に頼る必要はありません。

代わりに、トリプルシングルクォート文字列を使用しましょう。

def jsonContent = '''
{
    "name": "John",
    "age": 20,
    "birthDate": null
}
'''

Groovyはこれを単純なJava文字列として保存し、必要な連結と改行を追加します。

ただし、まだ克服すべき課題が1つあります。

通常、コードを読みやすくするために、コードをインデントします。

def triple = '''
    firstline
    secondline
'''

ただし、トリプルシングルクォート文字列は空白を保持します。 これは、上記の文字列が実際には次のことを意味します。

(newline)
    firstline(newline)
    secondline(newline)

いいえ:

1
2
    firstline(newline)
    secondline(newline)

おそらく私たちが意図したように。

私たちがそれらをどのように取り除くかを見るのを楽しみにしていてください。

4.1. 改行文字

前の文字列が改行文字で始まっていることを確認しましょう。

assertTrue(triple.startsWith("\n"))

そのキャラクターを取り除くことは可能です。 これを防ぐには、最初と最後の文字として1つの円記号\を付ける必要があります。

def triple = '''\
    firstline
    secondline
'''

今、私たちは少なくとも持っています:

1
2
    firstline(newline)
    secondline(newline)

1つ問題があり、もう1つ問題があります。

4.2. コードのインデントを取り除く

次に、インデントの世話をしましょう。 フォーマットは保持しますが、不要な空白文字は削除します。

Groovy String APIが役に立ちます!

文字列のすべての行の先頭のスペースを削除するには、Groovyのデフォルトメソッドの1つである String#stripIndent()を使用できます。

def triple = '''\
    firstline
    secondline'''.stripIndent()
assertEquals("firstline\nsecondline", triple)

目盛りを1行上に移動すると、 末尾の改行文字も削除しました。 

4.3. 相対インデント

stripIndentstripWhitespaceとは呼ばれないことを覚えておく必要があります。

stripIndent は、文字列内の短縮された非空白行からのインデントの量を決定します。

それでは、triple変数のインデントをかなり変更しましょう。

class TripleSingleQuotedString {

    @Test
    void 'triple single quoted with multiline string with last line with only whitespaces'() {
        def triple = '''\
            firstline
                secondline\
        '''.stripIndent()

        // ... use triple
    }
}

triple を印刷すると、次のように表示されます。

firstline
    secondline

の最初の行は、最もインデントされていない非空白行であるため、2番目の行はそれに対してインデントされたままゼロインデントになります。

また、今回は、前に見たように、末尾の空白をスラッシュで削除していることにも注意してください。

4.4. stripMargin()でストリップします

さらに細かく制御するために、|を使用してGroovyにラインを開始する場所を正しく指示できます。 およびstripMargin

def triple = '''\
    |firstline
    |secondline'''.stripMargin()

どちらが表示されますか:

firstline
secondline

パイプは、文字列のその行が実際にどこから始まるかを示します。

また、カスタム区切り文字を使用して、CharacterまたはCharSequenceを引数としてstripMarginに渡すことができます。

すばらしいです。不要な空白をすべて取り除き、文字列には必要なものだけが含まれています。

4.5. 特殊文字のエスケープ

トリプル一重引用符文字列のすべての利点により、文字列の一部である一重引用符と円記号をエスケープする必要があるという自然な結果があります。 

特殊文字を表すには、バックスラッシュでそれらをエスケープする必要もあります。 最も一般的な特殊文字は、改行( \ n )と集計( \ t )です。

例えば:

def specialCharacters = '''hello \'John\'. This is backslash - \\ \nSecond line starts here'''

結果は次のようになります。

hello 'John'. This is backslash - \
Second line starts here

覚えておく必要のあるものがいくつかあります。

  • \ t –集計
  • \ n –改行
  • \ b –バックスペース
  • \ r –キャリッジリターン
  • \\ –バックスラッシュ
  • \ f –フォームフィード
  • \’ –一重引用符

5. ダブルクォート文字列

二重引用符で囲まれた文字列もJavaStrings ですが、その特殊な機能は補間です。 二重引用符で囲まれた文字列に補間文字が含まれている場合、GroovyはJava StringGStringに切り替えます。

5.1。GStringと遅延評価

式を${} で囲むか、点線式の場合は $ で囲むことにより、二重引用符で囲まれた文字列を補間できます。

その評価は怠惰です、ただし– String を必要とするメソッドに渡されるまで、Stringに変換されません。

def string = "example"
def stringWithExpression = "example${2}"
assertTrue(string instanceof String)
assertTrue(stringWithExpression instanceof GString)
assertTrue(stringWithExpression.toString() instanceof String)

5.2. 変数を参照するプレースホルダー

補間で最初にやりたいことは、変数参照を送信することです。

def name = "John"
def helloName = "Hello $name!"
assertEquals("Hello John!", helloName.toString())

5.2. 式のあるプレースホルダー

しかし、私たちはそれに表現を与えることもできます:

def result = "result is ${2 * 2}"    
assertEquals("result is 4", result.toString())

ステートメントをプレースホルダーに入れることもできますが、それは悪い習慣と見なされます。

5.3. ドット演算子を使用したプレースホルダー

文字列内のオブジェクト階層を歩くこともできます。

def person = [name: 'John']
def myNameIs = "I'm $person.name, and you?"
assertEquals("I'm John, and you?", myNameIs.toString())

ゲッターを使用すると、Groovyは通常プロパティ名を推測できます。

ただし、メソッドを直接呼び出す場合は、括弧があるため、$ {} を使用する必要があります。

def name = 'John'
def result = "Uppercase name: ${name.toUpperCase()}".toString()
assertEquals("Uppercase name: JOHN", result)

5.4. hashCode in GStringおよびString

補間された文字列は、プレーンな java.util.String、と比較すると確かに天の恵みですが、重要な点で異なります。

Java Strings は不変であるため、特定の文字列に対して hashCode を呼び出すと、常に同じ値が返されます。

ただし、 String の表現は補間された値に依存するため、GStringハッシュコードはを変えることができます。

そして実際には、同じ結果の文字列であっても、同じハッシュコードはありません。

def string = "2+2 is 4"
def gstring = "2+2 is ${4}"
assertTrue(string.hashCode() != gstring.hashCode())

したがって、MapのキーとしてGStringを使用しないでください。

6. トリプルダブル引用文字列

つまり、トリプルシングルクォート文字列とダブルクォート文字列を見てきました。

両方の力を組み合わせて、両方の世界を最大限に活用しましょう–複数行の文字列補間:

def name = "John"
def multiLine = """
    I'm $name.
    "This is quotation from 'War and Peace'"
"""

また、一重引用符または二重引用符をエスケープする必要がないことに注意してください。

7. スラッシュストリング

ここで、正規表現を使用して何かを実行しているとしましょう。したがって、バックスラッシュをあちこちでエスケープしています。

def pattern = "\\d{1,3}\\s\\w+\\s\\w+\\\\\\w+"

それは明らかに混乱です。

これを支援するために、 Groovyはスラッシュ文字列を介してネイティブに正規表現をサポートします:

def pattern = /\d{3}\s\w+\s\w+\\\w+/
assertTrue("3 Blind Mice\Men".matches(pattern))

スラッシュ文字列は、補間と複数行の両方である可能性があります。

def name = 'John'
def example = /
    Dear ([A-Z]+),
    Love, $name
/

もちろん、スラッシュをエスケープする必要があります。

def pattern = /.*foobar.*\/hello.*/

コンパイラは//をコメントとして理解するため、空の文字列をSlashyStringで表すことはできません。

// if ('' == //) {
//     println("I can't compile")
// }

8. ドル-スラッシュ文字列

スラッシュ文字列は素晴らしいですが、スラッシュをエスケープする必要があるのは残念です。 スラッシュの追加のエスケープを回避するために、ドルスラッシュの文字列を使用できます。 

[0-3] + / [0-3]+という正規表現パターンがあると仮定します。 スラッシュ文字列では、 [0-3] + // [0-3] + と記述する必要があるため、ドルスラッシュ文字列の候補として適しています。

ドルスラッシュ文字列は、$ /で開き、/ $で閉じる複数行のGStringです。ドルまたはスラッシュをエスケープするには、ドル記号($)を前に付けることができますが、必須ではありません。

GStringプレースホルダーで$をエスケープする必要はありません。

例えば:

def name = "John"

def dollarSlashy = $/
    Hello $name!,

    I can show you a $ sign or an escaped dollar sign: $$ 
    Both slashes work: \ or /, but we can still escape it: $/
            
    We have to escape opening and closing delimiters:
    - $$$/  
    - $/$$
 /$

出力します:

Hello John!,

I can show you a $ sign or an escaped dollar sign: $ 
Both slashes work: \ or /, but we can still escape it: /

We have to escape opening and closing delimiter:
- $/  
- /$

9. キャラクター

Javaに精通している人は、Groovyが文字列に一重引用符を使用しているため、文字で何をしたのかすでに疑問に思っています。

実際、 Groovyには明示的な文字リテラルがありません。

3つの方法で、Groovy文字列を実際の文字にします。

  • 変数を宣言するときに「char」キーワードを明示的に使用する
  • ‘as’演算子を使用する
  • ‘char’にキャストする

それらすべてを見てみましょう:

char a = 'A'
char b = 'B' as char
char c = (char) 'C'
assertTrue(a instanceof Character)
assertTrue(b instanceof Character)
assertTrue(c instanceof Character)

最初の方法は、文字を変数として保持する場合に非常に便利です。 他の2つのメソッドは、関数の引数として文字を渡したい場合に、より興味深いものになります。

10. 概要

明らかに、それはたくさんありました、それでいくつかの重要なポイントを簡単に要約しましょう:

  • 一重引用符(’)で作成された文字列は補間をサポートしていません
  • スラッシュおよびトリプルダブルクォート文字列は複数行にすることができます
  • 複数行の文字列には、コードのインデントのために空白文字が含まれています
  • バックスラッシュ(\)は、ドル($)を使用してエスケープする必要があるドルスラッシュ文字列を除いて、すべてのタイプの特殊文字をエスケープするために使用されます

11. 結論

この記事では、Groovyで文字列を作成する多くの方法と、複数行、補間、および正規表現のサポートについて説明しました。

これらのスニペットはすべて、Githubから入手できます。

また、Groovy言語自体の機能の詳細については、Groovyの概要から始めてください。