🦁
Rust 文字列操作完全ガイド|よく使う26のメソッドまとめ
はじめに
Rustでは文字列操作が少し難しく感じる方も多いのではないでしょうか?
特に、&strとStringの違い、イテレータとの組み合わせ、Unicode対応など、慣れるまでは取っ付きづらく感じるかもしれません。
そこで本記事では、Rustにおける
よく使う文字列操作メソッド
初心者の方は「こんな書き方があるんだ」と知るきっかけに、経験者の方はリファレンスとして使えるようにまとめています。
今後のRust開発で文字列まわりの表現力を上げたい方は、ぜひ参考にしてみてください!
1. .trim() / .trim_start() / .trim_end() - 前後の空白や改行を削除
-
trim()は、前後の空白や改行を削除する。 -
trim_start()は、前方の空白や改行を削除する。 -
trim_end()は、後方の空白や改行を削除する。
fn main() {
let input = " Hello Rust! \n";
let trim = input.trim();
let trim_start = input.trim_start();
let trim_end = input.trim_end();
println!("{}", trim); // → Hello Rust!
println!("{}", trim_start); // → Hello Rust! \n
println!("{}", trim_end); // → Hello Rust!
}
2. .split_whitespace() - 空白で区切る
fn main() {
let input = "Hello Rust!";
for w in input.split_whitespace() {
println!("{}", w); // → Hello, Rust!
}
}
3. .replace() - 文字列の置換
fn main() {
let input = "Hello Rust!";
let input = input.replace("Rust", "World!");
println!("{}", input); // → Hello World!
}
4. .contains() - 部分一致を判定
fn main() {
let input = "Hello Rust!";
println!("{}", input.contains("Rust")); // → true
}
5. .starts_with() / .ends_with() - 前後の文字列を判定
-
.starts_with()は、指定した文字列で始まるかどうかを判定する。 -
.ends_with()は、指定した文字列で終わるかどうかを判定する。
fn main() {
let input = "Hello Rust!";
println!("{}", input.starts_with("Hello")); // → true
println!("{}", input.starts_with("hello")); // → false
println!("{}", input.ends_with("!")); // → true
println!("{}", input.ends_with("t")); // → false
}
.starts_with() + .ends_with() の応用チェック
fn main() {
let url = "https://example.com/";
println!(
"19.starts_with + ends_with: {}",
url.starts_with("https://") && url.ends_with("/")
); // → true
if url.starts_with("https://") && url.ends_with("/") {
println!("This is a valid URL");
}
}
6. .chars() + collect() - 1文字ずつ処理&文字列再構成
下記は、文字列を一文字ずつ処理して逆順に並べ直し、それをふだたび文字列(String)に変換している。
.rev()は、文字列を逆順にするメソッド。
.collect::<String>()は、イテレータを文字列に変換するメソッド。
fn main() {
let input = "Hello world!";
let reversed = input.chars().rev().collect::<String>();
println!("6.chars() + collect(): {}", reversed); // → "!dlrow olleH"
}
[処理のイメージ]
"Hello world!" → chars → ['H','e','l','l','o',' ','w','o','r','l','d','!']
↓
rev → ['!','d','l','r','o','w',' ','o','l','l','e','H']
↓
collect::<String>() → "!dlrow olleH"
7. .to_uppercase() / .to_lowercase() - 大文字 / 小文字に変換
fn main() {
let input = "Hello world!";
println!("7.to_uppercase(): {}", input.to_uppercase()); // → HELLO WORLD!
println!("7.to_lowercase(): {}", input.to_lowercase()); // → hello world!
}
8. .get(start..end) - サブ文字列の抽出(安全に)
fn main() {
let input = "hello world!";
if let Some(sub) = input.get(1..5) {
println!("8.get(start..end): {}", sub); // → ello
}
}
9. .join() - 配列やベクタの文字列結合
fn main() {
let words = vec!["Hello", "world!"];
let sentence = words.join(",");
println!("9.join(): {}", sentence); // → Hello,world!
}
10. .replacen() - 指定回数だけ置換
fn main() {
let input = "Hello Rust! Rust Rust !!";
let replaced = input.replacen("Rust", "workd", 2); // → Hello world! world Rust !!
println!("11.replacen(): {}", replaced);
}
11. .find() - 最初に一致する位置を取得(Option)
fn main() {
let input = "Hello Rust!";
if let Some(pos) = input.find("Rust") {
println!("Found at postion: {}", pos); // → 6
}
}
12. .rfind() - 最後に一致する位置を取得
fn main() {
let input = "a-b-c-b-a";
println!("13.rfind(): {}", input.rfind("b").unwrap()); // → 7
}
13. .char_indices() - インデックスと文字を両方取得
fn main() {
let input = "Rust";
for (i, c) in input.char_indices() {
println!("14.char_indices(): {} {}", i, c); // → 0 R, 1 u, 2 s, 3 t
}
}
14. .eq_ignore_ascii_case() - 大文字小文字を無視して比較
fn main() {
let a = "Hello";
let b = "hELLo";
println!("15.eq_ignore_ascii_case(): {}", a.eq_ignore_ascii_case(b)); // → true
}
15. .strip_prefix() / .strip_suffix() - 接頭・接尾を削る
-
strip_prefix()は、指定した文字列が先頭にある場合、それを削除した文字列を返す。 -
strip_suffix()は、指定した文字列が末尾にある場合、それを削除した文字列を返す。
fn main() {
let path = "/usr/bin/";
if let Some(cleaned) = path.strip_suffix("/") {
println!("16.strip_prefix(): {}", cleaned); // → /usr/bin
}
}
16. .repeat() - n回繰り返して新しい文字列を作る
fn main() {
let input = "Hello ";
println!("17.repeat(): {}", input.repeat(10));
}
17. .escape_default() - 特殊文字をエスケープ表記に
fn main() {
let input = "Hello\nRust!";
let escaped: String = input.chars().flat_map(|c| c.escape_default()).collect();
println!("{}", escaped); // → Hello\\nRust
}
18. .retain() - 条件を満たす文字だけ残す
fn main() {
let mut input = String::from("abc123456789");
input.retain(|c| c.is_ascii_alphabetic());
println!("{}", input); // → abc
}
20. .lines() - 行単位に分割する
fn main() {
let input = "line1\nline2\nline3";
for line in input.lines() {
println!("{}", line); // → line1, line2, line3
}
}
21. .split() / .splitn() / .rsplit() - 任意文字や回数で分割
-
.split()は、指定した文字で分割した結果をイテレータで返す。 -
.splitn()は、分割回数を指定できる。 -
.rsplit()は、右から分割する。
fn main() {
let input = "a:b:c:d";
let parts: Vec<&str> = input.split(":").collect::<Vec<&str>>(); // → ["a", "b", "c", "d"]
let parts_n: Vec<&str> = input.splitn(3, ':').collect::<Vec<&str>>(); // → ["a", "b", "c:d"]
let rparts: Vec<&str> = input.rsplit(":").collect::<Vec<&str>>(); // → ["d", "c", "b", "a"]
println!("{:?}", parts);
println!("{:?}", parts_n);
println!("{:?}", rparts);
}
22. .stars_with(char) / .contains(char) - 指定文字が含まれるか
fn main() {
let input = "hello";
println!("{}", input.starts_with('h')); // → true
println!("{}", input.contains('e')); // → true
}
23. .is_empty() - 空文字判定
fn main() {
let input = "";
if input.is_empty() {
println!("input is empty");
}
}
24. .truncate(n) - n文字目以降をカット(可変String用)
fn main() {
let mut input = String::from("Hello world!");
input.truncate(5);
println!("{}", input); // → Hello
}
25. .replace_rang() - 一部の文字列を範囲指定で置換(String専用)
fn main() {
let mut input = String::from("abcdef!");
input.replace_range(2..4, "XY"); // → abXYef!
println!("{}", input);
}
26. .match_indices() - パターンが現れるインデックスと内容を取得
fn main() {
let input = "ababad aba aba xxx aba";
for (i, s) in input.match_indices("aba") {
println!("{} {}", i, s); // → 0 aba, 7 aba, 11 aba 19 aba
}
}
おわりに
Rustの文字列操作は、慣れるととても表現力が高く、正確で安全です。
本記事で紹介した .trim(), .split(), .replace(), .collect() などの基本メソッドに加え、
.retain(), .match_indices(), .strip_prefix() などの応用メソッドも使いこなせば、かなり自由度の高い文字列処理が書けるようになります。
最後まで読んでいただきありがとうございました。
もし「他にもこんな操作があるよ!」という方がいれば、ぜひコメントなどで教えてください!
Discussion