【Rust】文字列関数まとめ
プログラムを書く上で文字列の扱いは非常に重要です。
他のプログラミング言語で簡単に出来ていた文字列処理を、
Rustでもできるように基本的な文字列関数をまとめました。
文字列生成
一番基本的な方法
1 2 3 4 |
fn main() { let s = String::from("rust string sample"); } |
初期化をしてそれを後で使用するなどしたい場合はnewを使います。
例えばこんな具合に。
1 2 3 4 5 |
fn main() { let mut name = String::new(); std::io::stdin().read_line(&mut name).expect("failed stdin"); } |
長さを取得
文字列の長さを取得したい場合ももちろんあります。
Rustにはそのための関数が用意されています。
1 2 3 4 5 |
fn main() { let mut name = String::new(); std::io::stdin().read_line(&mut name).expect("failed stdin"); } |
長さとは違う話かもしれません。
with_capacityを使うことで文字列が使うバッファーを前もって割り当てることができます。
1 2 3 4 5 6 7 |
fn main() { let mut str = String::with_capacity(30); for _ in 0..30 { str.push('a'); } } |
これをして何の意味があるのか。
どうも再割り当てを防ぐためらしいです。
文字列連結などで文字数が増える場合、その分だけ文字列が使うメモリを増やさなければいけません。
前もってバッファを割り当てておけばこの処理を省くことができるという魂胆のようです。
連結、拡張
様々な方法の文字列連結があります。
これはstring型にstr型を連結するサンプルです。
1 2 3 4 5 |
fn main() { let mut str = String::from("rust string"); str.push_str(" sample"); } |
stringとstringを連結する場合、これとは方法が少し違います。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
fn main() { let mut s = String::from("rust string"); s.push_str(" sample"); let s2 = String::from(" program"); let mut s3 = s + &s2; s = String::from(" rust string"); s3.push_str(s.as_str()); } |
1 |
let mut s3 = s + &s2; |
+演算子で連結できます。
その場合連結元には&をつけ参照を渡します。
この例では変数s3に結果を渡しています。
ちなみにここで変数sのリソースの所有権がs3に渡ったためこの処理の後、
変数sを使うことはできません。
幸いなことに変数s2は使えます。
1 |
s3.push_str(s.as_str()); |
push_strで連結したい場合、string型をstr型に変換する必要があります。
分裂
rustには文字列を配列(vec)にしてくれる関数が用意されています。
1 2 3 4 5 6 7 8 9 |
fn main() { let s = String::from("rust string sample program"); let v: Vec<&str> = s.split(' ').collect(); for i in &v { //なにかやる } } |
最も基本的な分裂関数はsplitです。
デリミタを渡します。
返り値はSplit型なのでcollectでvecに変換しています。
ちなみにrsplitというものもありまして、
こちらは文字列を逆から分解していくものです。
また分解数を指定することもできます。
1 2 3 4 5 6 7 8 9 |
fn main() { let s = String::from("rust string sample program"); let v: Vec<&str> = s.splitn(2, ' ').collect(); for s in &v { } } |
ここでは分解数を2にしています。
その結果文字列は「rust」と「string sample program」にわけられます。
一回だけ分解したい場合などにも使えそうですね。
検索
検索です。
1 2 3 4 5 6 7 |
fn main() { let s = "rust string sample program"; let res = s.find("rust").unwrap; println!("{}",res); } |
検索対象の文字列にパターンが含まれいる場合、
その場所(インデックス)を返してくれます。
返ってくる型はoption型なのでunwrapする必要があります。
上の例ではunwrap関数で開けてますが、
これだとマッチしていない場合パニックを起こしプログラムが終了します。
この辺りはいろいろ対策をする必要があるかと思います。
またマッチした文字列すべてを取得することもできます。
1 2 3 4 5 6 |
fn main() { let s = String::from("rust string sample program rust i like rust"); let v: Vec<&str> = s.matches("rust").collect(); } 結果 ["rust", "rust", "rust"] |
matchesにパターンを渡します。
返ってくるのはMatchesです。
先の例と同じようにcollectを使いvecに変換しています。
vec(ここでは変数v)にはパターンにマッチした文字列すべてが格納されています。
文字列がパターンにマッチした場所を得ることもできます。
1 2 3 4 5 6 7 |
fn main() { let s = String::from("rust string sample program rust i like rust"); let v: Vec<_> = s.match_indices("rust").collect(); } [(0, "rust"), (27, "rust"), (39, "rust")] |
マッチした文字列とともに文字列が見つかった場所(インデックス)が返ってきます。
置換
文字列置換です。
1 2 3 4 5 6 |
fn main() { let s = "rust string sample program"; let s2 = s.replace("string", "replace"); } 結果 rust replace sample program |
replace関数に置換対象文字列と置換文字列を渡します。
また置換する回数を指定することもできます。
1 2 3 4 5 6 |
fn main() { let s = "python c ruby java python c# python javascript"; let s2 = s.replacen("python", "rust", 2); } |
まとめ
Rustには他にも文字列関数が用意されています。
nightlyでしか使えないものもあるようです。
ただ、上にあげた関数だけでも多くのことができそうですね。