今回はKotlinの文字や文字列に関する基礎知識を1ページにまとめます。コメントやエスケープ、ヒアドキュメントの使い方から、String型の基本操作(連結、繰り返し、文字の抽出、インデックス番号の取得など)を行うメソッドの紹介です。
文字表記の基本
まずはKotlinにおける文字や文字列の仕様をおさらいしておきましょう。
String型とChar型/コメントの書き方
Kotlinでは文字と文字列は区別されます。コメントは1行の場合//
、複数行の場合/**/
で囲みます。
val str = "Kotlin" //文字列はString型。ダブルクオートで囲む
val chara = 'a' //1文字限定のChar型。シングルクオートで囲む
val str2 = "a" //1文字でもダブルクオートで囲んだ場合、String型となる
val n = '\n' //1文字を表すのであればChar型で表せる
/*
コメントが複数行になる場合、
このように記述。
*/
エスケープ文字
改行、タブ文字などを表すにはエスケープ文字\
を利用します。
入力 | 出力 |
---|---|
\n | 改行 |
\n\r | 改行と復帰(Win) |
\t | タブ文字 |
\b | BackSpace |
\’ | ‘ |
\” | “ |
\\ | \ |
\$ | $ |
\u | Unicode文字を番号で指定 (例: \u7832 = 砲) |
val str = "\"Kotlin\"って\nマジで\b\n\tかわいいよね"
println(str)
/*
"Kotlin"って
マジ
かわいいよね
*/
複数行文字列 (ヒアドキュメント)
複数行の文字列を1つの値として扱うヒアドキュメント。開始と終了をダブルクオート3つで囲みます。
エスケープは効かず、そのまま出力されるため「生文字列」とも呼ばれます。
val str = """
この中に書いた文字列は
改行なども含めて1つの値。
エスケープされた文字も\nそのまま出力される
"""
println(str)
/*
この中に書いた文字列は
改行なども含めて1つの値。
エスケープされた文字も\nそのまま出力される
*/
変数や式の展開 (文字列テンプレート)
文字列の中に変数を展開したり式を埋め込む「文字列テンプレート」は、${}
の波括弧の中に式を挿入します。この${}
もダブルクオートの中に入れるということに注意しましょう。
val str = "展開"
val str2 = "文字列の$str" //後にスペース、もしくは何も続かない場合、波括弧は不要
//文字列の展開
val num = 10
println("${num}の5倍は${num*5}") //数値や式も展開可能。式の展開は波括弧が必要
//10の5倍は50
println("$num*5")
//10*5
String型の基本操作とメソッド
ここからはその他の文字列操作に関して基本的なところを押さえておきます。
文字列はイミュータブルのため、呼び出し元を変更する破壊的なメソッドはありません。println()
は省略している部分も多々ありますが、結果を変数に入れるなどして利用してください。
String型のAPIリファレンスは以下で確認できます。
文字列の連結
文字列や数値は+
で連結することができます。
val str1 = "プレミア"
val str2 = "チケット"
str1+str2 //プレミアチケット
//数値+文字列は自動的に文字列として扱われる
val str3 = 12
str1+str3 //プレミア12
同じ処理はplus
メソッドでも可能。
println(str1.plus(str2))
//プレミアチケット
文字列の繰り返し
ある文字列を繰り返すにはrepeat
メソッドを使います。演算子*
による繰り返しは、Kotlinでは基本的にできません。
repeat
fun CharSequence.repeat(n: Int): String
"にこ".repeat(2) //にこにこ
//0を指定すると空文字列に
"にこ".repeat(0) //""
インデックス番号を取得する
ある文字のインデックス番号を取得するにはindexOf
やlastIndexOf
を使用します。
indexOf
fun CharSequence.indexOf(
char: Char, //String型でも可
startIndex: Int = 0,
ignoreCase: Boolean = false
): Int
通常は引数1つで指定した文字が初めて現れるインデックス番号を出力。
val str = "Hey, Dad, I need your help!"
//引数1つ。大文字小文字の違いを判定の要素とする
str.indexOf('d') //7
//引数2つ。第2引数で検索開始インデックスを指定
str.indexOf('d', 7) //15
//引数3つ。第3引数で大文字小文字を無視するかどうかを指定
str.indexOf('d', 0, true) //5
//指定文字が見つからない場合、-1を出力
str.indexOf('z') //-1
lastIndexOf
fun CharSequence.lastIndexOf(
char: Char,
startIndex: Int = lastIndex,
ignoreCase: Boolean = false
): Int
indexOf
の逆。指定文字が最後に現れるインデックス番号を出力します。
文字列の最後から検索し始めるという点に注意しましょう。第2引数のデフォルトは文字列の最後の文字のインデックス番号です。
val str = "Hey, Dad, I need your help!"
str.lastIndexOf('d') //15
//第2引数が0だと最初の文字しか検索しない
str.lastIndexOf('d', 0) //-1
1文字を抽出する
ある文字列から一部分を抽出する方法は複数存在します。まずは文字列から「1文字」を抜き出す方法です。
インデックス番号を指定する / elementAt
文字列は文字を並べたシーケンスです。そのため文字列からの部分的な抽出は、以下のようにインデックス番号を利用することができます。
またelementAt
メソッドでも同じ結果が得られます。インデックス番号に対応した文字が呼び出し元に無い場合、「IndexOutOfBoundsException」を送出。
fun CharSequence.elementAt(index: Int): Char
val str = "oll korrect"
//インデックス番号指定。戻り値の型はChar型
println(str[6]) //r
//elementAtメソッドでも同じ
println(str.elementAt(6)) //r
//Char型のため、そのまま足し合わせることは不可
str[0] + str[4] //エラー: Type mismatch
//String + CharはOK
str[0].toString() + str[4] //ok
elementAtOrElse / elementAtOrNull
inline fun CharSequence.elementAtOrElse(
index: Int,
defaultValue: (Int) -> Char
): Char
fun CharSequence.elementAtOrNull(index: Int): Char?
例外を嫌う場合はこちら。文字列から呼び出す場合、戻り値はChar(Char?)型であることに注意。
val str = "oll korrect"
str.elementAtOrElse(20){'無'} //無
str.elementAtOrNull(20) //null
first / last
fun <T> Iterable<T>.first(): T
fun <T> Iterable<T>.last(): T
文字列の最初や最後の文字を抽出するにはfirst
/last
の各メソッドが簡単な手段です。
val str = "Kotlin"
//イテラブルの最初の要素を出力
str.first() //K
//イテラブルの最後の要素を出力
str.last() //n
レシーバがイテラブルであればどんな型でも応用が効く、シンプルかつ柔軟なメソッドでもあります。
val l = listOf(null, 2, 3, null)
//null許容型もOK
l.first() //null
文字列を抽出する
続いて文字列から複数文字を抽出するメソッド。
substring
fun String.substring(startIndex: Int): String
fun String.substring(startIndex: Int, endIndex: Int): String
fun String.substring(range: IntRange): String
連続する文字列を抽出するにはsubstring
。いつものクセで後半の「string」を大文字にしてしまわないように注意してください。表記は全て小文字です。
val str = "シン・ゴジラ"
//指定したインデックス以降の文字列を取得
str.substring(4) //ジラ
//引数2つ。インデックス0から1までを取得
str.substring(0, 2) //シン
//IntRange型を使っても同じ
str.substring(0 until 2) //シン
//ドット2つで範囲指定すると、指定したインデックスまで含まれる
str.substring(0..2) //シン・
slice
fun String.slice(indices: IntRange): String
fun String.slice(indices: Iterable<Int>): String
続いてslice
。substring
とは違い、引数は1つのみ。
//substringと同じ結果
str.slice(0 until 2) //シン
//これも結果はsubstringと同じ
str.slice(0..2) //シン・
//引数は1つのみ
str.slice(0, 2) //エラー: None of the following functions...
slice
が特徴的なのはイテラブルオブジェクトを引数として取れる点。これによって連続しない複数の文字を抽出することができます。
val str = "キングギドラとメカゴジラ"
val l = listOf<Int>(3, 7, 11)
str.slice(l) //ギメラ
上のコードではListを使い、インデックス番号3,7,11に対応する文字を取り出しています。
文字列から一部を削除する
drop / dropLast
fun String.drop(n: Int): String
fun String.dropLast(n: Int): String
呼び出し元のStringからn文字削除します。
val str = "Kotlin"
//dropは最初からn文字削除
str.drop(2) //tlin
//dropLastは最後からn文字削除
str.dropLast(2) //Kotl
dropWhile / dropLastWhile
inline fun String.dropWhile(
predicate: (Char) -> Boolean
): String
ラムダ式の条件に当てはまるものを削除。一度でもラムダ式の結果がfalseになれば、以降は削除しません。
val str = "---Kotlin---"
str.dropWhile {it == '-'} //Kotlin---
str.dropLastWhile { it == '-'} //---Kotlin
文字列の前後の空白/その他不要な文字を除去する
trim
fun String.trim(): String
fun String.trim(vararg chars: Char): String
文字列前後の空白や指定文字を除去。中に含まれる空白は除去しません。
引数を指定しなければ空白文字のみ、Char型を複数指定することも可能。
val str = " K o t l i n "
str.trim() //K o t l i n
val str = "ooo ,Kotlin, ooo"
//引数はChar型
str.trim(',', ' ', 'o') //Kotlin
文字列を別の文字列と入れ替える
ある文字や文字列を別の文字に入れ替えるにはreplace
を使用します。
replace
fun String.replace(
oldValue: String, //Char型も可
newValue: String, //Char型も可
ignoreCase: Boolean = false //大文字小文字を区別するか
): String
基本的には第一引数に置き換え対象、第二引数に置き換え先の文字(列)を指定。
val str = "あつまれ どうぶつの森"
//あつまれ を おいでよ に入れ替え
val str2 = str.replace("あつまれ", "おいでよ")
println(str2) //あつまれ どうぶつの森
文字列を分割する
split
は呼び出し元の文字列を指定したデリミタ(区切り文字)で区切り、複数の値として取り出します。
split
fun CharSequence.split(
vararg delimiters: String,
ignoreCase: Boolean = false,
limit: Int = 0
): List<String>
必須引数は1つ、デリミタの指定のみ。
val str = "いい数字,出るまで測る,血圧計"
//カンマをデリミタに指定。出力はList<String>
val a = str.split(",") //[いい数字, 出るまで測る, 血圧計]
大文字小文字を変換する
大文字小文字を変換するには3つのメソッド、toUpperCase
、toLowerCase
、capitalize
を使用します。
toUpperCase / toLowerCase / capitalize
fun String.toUpperCase(): String //全て大文字に変換
fun String.toLowerCase(): String //全て小文字に変換
fun String.capitalize(): String //先頭文字を大文字に変換
メソッドの使い方は単純なので、こちらでは少し応用編。カンマで区切られた文字列の各先頭文字を大文字にしてみます。
val str = "hello, kotlin"
//hとkを大文字にしたい
val str2 = str.split(", ").map { it.capitalize() }.joinToString(", ")
println(str2) //Hello, Kotlin
split
で文字列をListに分割- Listを
map
にかけ、各要素をcapitalize
してListを返す joinToString
でListから文字列に戻す
という一連の処理をメソッドチェーンで実施。
decapitalize
fun String.decapitalize(): String
capitalize
の逆。最初の文字を小文字に変換します。
val str = "Kotlin"
println(str.decapitalize()) //kotlin