1. 概要

このチュートリアルでは、Kotlinで文字列の一部を別の文字列に置き換えるいくつかの方法を学習します。

2. 単一文字の置き換え

文字列内の1文字を置き換えるために、 replace(oldChar、newChar)拡張関数を使用できます。

val txt = "I am a robot"
val replaced = txt.replace('a', 'A')
assertEquals("I Am A robot", replaced)

上に示したように、この特定のメソッドは、最初の引数のすべての出現箇所を2番目の引数に置き換えるだけなので、非常に簡単です。

Koltinのreplaceextension関数のすべてのバリエーションは、その場で変更するのではなく、新しい文字列を返すことに注意してください。 これは、Kotlinでは文字列が不変であるためです。

デフォルトでは、 replace(oldChar、newChar)メソッドは大文字と小文字の区別を考慮します。 ただし、オプションの ignoreCase パラメーターを最後の引数として渡すことで、この設定を無効にすることができます。

val replaced = txt.replace('i', 'i', ignoreCase = true)
assertEquals("i am a robot", replaced)

ここでは、小文字と大文字の両方の「i」文字(最初と3番目の引数で指定)を探し、それらを小文字の文字(2番目の引数)に置き換えています。

3. 部分文字列の置き換え

単一の文字に加えて、サブ文字列をターゲット文字列内の他の文字列に置き換えることもできます。

val txt = "I am a robot"
val replaced = txt.replace("robot", "human")
assertEquals("I am a human", replaced)

上に示したように、「ロボット」文字列全体が「人間」に置き換えられます。 同様に、最後の引数としてブールフラグを渡すことにより、大文字と小文字を区別しないバージョンを有効にすることができます

val replaced = txt.replace("i am a", "we are", true)
assertEquals("we are robot", replaced)

4. 正規表現での置き換え

単純な文字シーケンスに加えて、正規表現を使用してパターンを置き換えることができます。

val txt = "<div>This is a div tag</div>"
val regex = "</?.*?>".toRegex() // matches with every <tag> or </tag>
val replaced = txt.replace(regex, "")
assertEquals("This is a div tag", replaced)

ここで、replace(pattern、newString)は、出現するすべてのHTMLタグを空の文字列に置き換えます。 基本的に、すべてのHTMLタグを削除します。

非常に興味深いことに、(MatchResult)-> CharSequence lambda を渡して、一致した部分に基づいて置換文字列を決定できます。 たとえば、ここでは、一致した部分を大文字にしているだけです。

val replaced = txt.replace(regex) {
    it.value.toUpperCase()
}
assertEquals("<DIV>This is a div tag</DIV>", replaced)

上に示したように、指定されたラムダで必要なものを返すことにより、置換文字列を動的に決定できます。

5. 最初の発生を置き換える

これまで、単一の文字、文字列、またはパターンのすべての出現箇所を置換文字列に置き換えてきました。 これに加えて、最初のオカレンスだけをいくつかの特殊なオーバーロードされた拡張関数に置き換えることも可能です。

単一の文字の最初の出現を別の文字に置き換えるために、 replaceFirst(oldChar、newChar)拡張関数を使用できます。

val txt = "I am a robot"
val replaced = txt.replaceFirst('a', 'A')
assertEquals("I Am a robot", replaced)

上に示したように、最初の‘a’のみが大文字バージョンに置き換えられます。 同様に、最初に一致したサブストリングを別のストリングに置き換えるためのバリアントがあります。

val txt = "42 42"
val replaced = txt.replaceFirst("42", "The answer is")
assertEquals("The answer is 42", replaced)

どちらのバージョンも、デフォルトでは大文字と小文字が区別され、オフにする機能もサポートしています。 そして最後に、正規表現の最初の出現を置き換えるためのオーバーロードバージョンがあります。

val txt = "<div>this is a div</div>"
val replaced = txt.replaceFirst("</?.*?>".toRegex(), "")
assertEquals("this is a div</div>", replaced)

当然のことながら、ここでは最初のHTMLタグのみが削除されています。

6. 範囲の交換

文字列内のある範囲の文字を、いくつかの異なる方法で別の文字に置き換えることも可能です。 これらのアプローチに慣れましょう。

6.1. 数値範囲

文字の範囲を置き換えるために、 replaceRange(startIndex、endIndex、replacement)拡張関数を使用できます。

val txt = "42 is the answer"
val replaced = txt.replaceRange(0, 3, "")
assertEquals("is the answer", replaced)

いつものように、 startIndexは包括的であり、endIndexは排他的です。 したがって、この例では、基本的に最初の3文字を空の文字列に置き換えています。

Kotlinはrangesをファーストクラスでサポートしているため、 replaceRange(intRange、replacement)拡張関数を使用してIntRange構文を使用できます。

assertEquals("is the answer", txt.replaceRange(0..2, ""))
assertEquals("is the answer", txt.replaceRange(0 until 3, ""))

最初の例では、“ 0..2” は閉じた範囲を作成します(開始インデックスと終了インデックスの両方が含まれます)。 したがって、最初の例では、最初の3文字を空の文字列に置き換えます。 一方、2番目の例ではオープンレンジが作成されるため、終了位置は排他的です。 したがって、同じ出力を実現するには、「0から3」構文を使用する必要があります。

6.2. 範囲の前

明示的なint範囲に加えて、文字または文字列の前のすべてを置換文字列で置き換えることができます。

assertEquals("is the answer", txt.replaceBefore('i', ""))
assertEquals("is the answer", txt.replaceBefore("is", ""))

上記の例では、文字‘i’および文字列「is」が最初に出現する前のすべての文字が空の文字列に置き換えられます。

デフォルトでは、指定された検索文字または文字列に一致するものがない場合、 replaceBefore()は文字列全体をそのまま返します。

assertEquals("42 is the answer", txt.replaceBefore("not a match", ""))

ただし、3番目の引数を渡すことにより、一致しない場合に別の文字列を返すこともできます。

assertEquals("default", txt.replaceBefore("not a match", "", "default"))

上に示したように、指定された文字列に一致するものがないため、関数は「デフォルト」文字列を返します。

デフォルトでは、 replaceBefore()関数は、指定された引数が最初に出現する前にすべてを置き換えます。 replaceBeforeLast()オーバーロードバージョンを使用して、指定された文字の最後の出現に基づいて同じことを行うことも可能です。

assertEquals("swer", txt.replaceBeforeLast('s', ""))

ここで、文字はテキスト内で2回出現し、上記の関数は最後の出現を置換の終点として選択します。

6.3. アフターレンジ

replaceBefore()と非常によく似ており、逆に機能する拡張関数がいくつかあります。 つまり、特定の文字または文字列が最初または最後に出現した後、すべての文字を置き換えることができます。

assertEquals("42 i", txt.replaceAfter('i', ""))
assertEquals("42 is", txt.replaceAfter("is", ""))
assertEquals("42 is the answer", txt.replaceAfter("not a match", ""))
assertEquals("default", txt.replaceAfter("not a match", "", "default"))
assertEquals("42 is the ans", txt.replaceAfterLast('s', ""))

上に示したように、これらのオーバーロードされた関数は、前のセクションで見たものと非常によく似ています。

7. くぼみの交換

replaceIndent()拡張関数を使用して、開始インデント(1つ以上のスペースで始まる文)を削除できます。

assertEquals("starts with indent", "    starts with indent".replaceIndent())

上に示したように、 replaceIndent()関数は、文の先頭にあるいくつかの余分なスペースを削除します。 非常に興味深いことに、これらのインデントを他の文字列に置き換えることもできます

assertEquals("==> starts with indent", "    starts with indent".replaceIndent("==> "))

ここでは、最初の余分なスペースを“ ==>”マーカーに置き換えています。

8. その他の機能

名前にreplaceプレフィックスが含まれていない関数もありますが、それらのいくつかは置換機能に関連しています。 このセクションでは、それらのいくつかに精通します。

8.1. トリミング

トリム関連のAPIは、文字列の最初または最後からいくつかの文字セットを削除するのに役立ちます。 前のセクションでは、すべてのスペース文字を空の文字列に置き換えることができることを確認しました。

assertEquals("both ends", " both ends ".replace(" ", ""))

このように、基本的に文字列の両端から余分なスペースをトリミングしています。 幸いなことに、拡張機能の柔軟性のおかげで、Kotlinでこれを実現するためのはるかに簡単な方法があります。

たとえば、 Trim()拡張関数は、文字列の両端から余分なスペースを削除します。

assertEquals("both ends", "  both ends ".trim())

この関数は、デフォルトでスペース文字を検索しますが、トリム文字を変更できます。

assertEquals("both ends", "###both ends!!".trim('#', '!'))

上記の例では、トリム文字として、スペースではなくハッシュタグと感嘆符を検索するようにtrim()に明示的に指示しています。 述語ラムダを渡して、トリム文字を動的に決定することも可能です。

assertEquals("both ends", "#?!both ends@".trim { !it.isLetter() && it != ' ' })

ここでは、文字とスペース文字を除くすべての文字がトリム文字と見なされます。

Trim()とは対照的に、 TrimStart()関数は、文字列の先頭からのみスペース文字を(デフォルトで)削除します。

assertEquals("just the beginning  ", "  just the beginning  ".trimStart())
assertEquals("just the beginning##", "##just the beginning##".trimStart('#'))
assertEquals("just the beginning  ", " #%just the beginning  ".trimStart { !it.isLetter() })

上記のように、文字列の先頭からスペース文字を削除しても、トリム文字は構成可能です。 trimEnd()拡張関数を使用して、文字列のもう一方の端に対して同じことを行うことができます。

assertEquals("  just the ending", "  just the ending  ".trimEnd())
assertEquals("##just the beginning", "##just the beginning##".trimEnd('#'))
assertEquals(" #%just the beginning", " #%just the beginning  ".trimEnd { !it.isLetter() })

幸いなことに、トリム関連のAPIは、APIシグネチャの点で互いに非常に似ています。 したがって、デフォルトでは、それらすべてでスペース文字が削除されます。 ただし、トリム文字は静的文字のセットに変更することも、ラムダ関数によって動的に決定することもできます。

8.2. 削除

これまで、いくつかの置換方法を使用して、文字列の一部を空の文字列に置き換えてきました。 代わりに空の文字列を明示的に言及する代わりに、いくつかの特別な関数を使用して、文字列から対象の部分を簡単に削除できます。

trimStart()と同様に、 removePrefix(prefix)と呼ばれる別の拡張関数があり、任意の文字列からプレフィックスを削除できます。

assertEquals("single line comment", "//single line comment".removePrefix("//"))

ここでは、指定された文字列の先頭から“ //”マーカーを削除しています。 同様に、文字列から特定のサフィックスを削除できます。

assertEquals("end of multiline comment", "end of multiline comment*/".removeSuffix("*/"))

さらに、文字列の最初と最後の両方から削除することができます。

assertEquals("some regex", "/some regex/".removeSurrounding("/"))

上記の関数は、文字列が指定された引数で始まり、終わる場合にのみ機能します。 それ以外の場合は、同じ文字列がそのまま返されます。

assertEquals("/sample", "/sample".removeSurrounding("/"))

文字列は“ /” で終わらないため、 removeSurrounding()は同じ文字列を返します。 文字列の両端から異なるプレフィックスとサフィックスを削除するには、 removeSurrounding(prefix、suffix)extension関数を使用できます。

assertEquals("multiline comment", "/*multiline comment*/".removeSurrounding("/*", "*/"))

同様に、この関数は、文字列が指定されたプレフィックスで始まり、指定されたサフィックスで終わる場合にのみ機能します。

最後に、 removeRange()拡張関数を使用して、指定された文字列内の文字の範囲を削除することもできます。

assertEquals("a robot", "I'm a robot".removeRange(0..3))
assertEquals("a robot", "I'm a robot".removeRange(0 until 4))

replaceRange()と同様に、この関数はKotlinの範囲構文を受け入れます。 上記の例では、“ 0..3” 構文によって閉じた範囲が作成されるため、3番目のインデックスの文字も削除されます。 「0から4」はオープンレンジを作成するため、2番目の例には当てはまりません。

開始インデックスと終了インデックスを別々の引数として渡すことも可能です。

assertEquals("a robot", "I'm a robot".removeRange(0, 4))

いつものように、終了インデックスは排他的であるため、4番目のインデックスの文字は削除されません。

8.3. 一部の文字を削除する

drop(n:Int)拡張関数は、文字列の先頭から最初のn文字を削除します

assertEquals("is the answer", txt.drop(3))

ここでは、最初の3文字を削除しています。 逆に、最後のn文字も削除できます。

assertEquals("42 is the", txt.dropLast(7))

条件がtrueのときに、文字列の先頭から文字を削除することも可能です。

assertEquals(" is the answer", txt.dropWhile { it != ' ' })

ここでは、最初のスペース文字に出会うまですべての文字を削除しています。 同様に、文字列の反対側からも同じことができます。

assertEquals("42 is the ", txt.dropLastWhile { it != ' ' })

8.4. いくつかのキャラクターを取る

drop *()拡張関数のセットとは対照的に、拡張関数のtake *()セットを使用して、文字を削除する代わりにそれらを保持できます。 たとえば、文字列の先頭から最初の n 文字だけを保持するには、 take(n:Int)を使用できます。

assertEquals("42", txt.take(2))

ここでは、最初の2文字を保持し、残りの文字列を破棄しています。 残りのtake関連のAPIは、drop関連のAPIで見たものと非常によく似ています。

assertEquals("answer", txt.takeLast(6))
assertEquals("42", txt.takeWhile { it != ' ' })
assertEquals("answer", txt.takeLastWhile { it != ' ' })

9. 結論

拡張機能の柔軟性のおかげで、Kotlinは、関連する機能の置き換えを含む、文字列操作のための非常に豊富なAPIを提供します。 この記事では、正規表現や範囲とのマッチングなど、さまざまな方法で文字列の一部をさまざまな置換に置き換える方法を数多く見てきました。

いつものように、すべての例はGitHubから入手できます。