LoginSignup
169
116

More than 5 years have passed since last update.

Rustの文字列操作

Last updated at Posted at 2015-02-10

Rustにおいて、文字列関係の型は3種類ある。

文字を表すchar

charはユニコードのコードポイントと一対一に対応する

let ch: char = 'a';
assert_eq!(ch as u32, 0x61);  // 32bit整数にキャスト出来る

文字列リテラルは&str

文字列版のスライス
なので、変更可能ではない

let s: &str = "文字列";

通常の変更可能な文字列クラスはString

let string: String = String::new();

&strStringは、C/C++におけるconst char *なリテラルと文字列クラスstd::stringみたいなもの

String&stras_slice()to_string()で交互に変換できる。
ただし、to_string()は新しくStringを作り、文字列をコピーする。as_slice()は参照するだけなのでコストは小さい

"abc".to_string().as_slice();

Rustの文字列はutf-8の文字列でなければならない
もし変なバイトが含まれているとエラーになる

String::from_utf8(b"\xbb".to_vec()).unwrap();  // Error!

文字列操作で気をつける点

2つの&strを簡単にくっつける方法は無い

リテラルならconcat!マクロを使うとコンパイル時にまとめてくれる

println!("{}", concat!("abc", "def", 0, 1.2));

リテラル以外の場合はformat!()が簡単でおすすめ

println!("{}", format!("{}{}", "abc", "def"));

左側がStringで、かつ過去を振り返らないなら"+"演算子が使える

let (a, b) = ("abc".to_string(), "def");
println!("{}", a + b);  // 今後aを参照するとコンパイルエラー

結論としては、concat!format!を使うのが良い。+演算子は使える条件が厳しいので使わないほうが良い。
例外として、mutableなStringに文字列を追加する時に使ったり出来るが、同じ意味のpush_str()を使うほうがいいと思う

let mut c = "a".to_string();
c = c + "b";
c.push_str("c");  // push()は一文字足す、push_str(&str)は文字列を足す

文字列のスライス操作はなるべく避け、使うときは特徴を把握する

文字列はUTF-8で格納されているので、slice_chars(i, j)O(j)のコストがかかる。

assert_eq!("い", "あいう".slice_chars(1, 2));

s[i]のように気軽にインデックスアクセス出来ない。先頭と末尾は次のようにすると楽。

assert_eq!('あ', "あいう".char_at(0));
assert_eq!('う', "あいう".char_at_reverse("あいう".len()));

もし頻繁にインデックスアクセスを行いたい場合には、chars()で文字配列を作れば良い

"あいう".chars().collect::<Vec<char>>();

中のバイト列が欲しい時にはbytes()やas_bytes()を使う

println!("s[0](byte)={}", s.as_bytes()[0]);

文字列のフォーマットはformat!()マクロで。println!()と同じsyntaxで使える

assert_eq!("0.123", format!("{:.3}", 0.123456));

正規表現は組み込みじゃない

stdには含まれないので、ライブラリを使う事。

よく使われる文字列操作からピックアップ

文字数

そのうちchar_len()が使えるようになるかも

assert_eq!(3, "あいう".chars().count());

文字列の結合(join)

assert_eq!("Hello World", ["Hello", "World"].connect(" "));

こちらは単に結合するだけ。一般のVecに対するflatternメソッドとして使える

let d: String = ["Hello", "World"].concat();
assert_eq!("HelloWorld", d);

文字列の分割

"a.b.c".split('.');  // => iterator of ["a", "b", "c"]
"a..b..c".split_str(".");  // => iterator of ["a", "b", "c"]

置換

assert_eq!("adeade", "abcabc".replace("bc", "de"));  // replaceはin-place演算ではない。新しい文字列を作って返す

部分文字列が含まれているか調べる

assert!("abc".starts_with("ab"));
assert!(!"abc".starts_with("cb"));
assert!("abcd".contains("bc"));
assert_eq!(Some(2), "abcde".find_str("cd"));

部分文字列を得る

assert_eq!("b", "abc".slice_chars(1, 2));

部分文字列の出現回数をカウントする

対応するメソッドがないのでmatch_indicesを介する

assert_eq!(2, "xabxxabxxbc".match_indices("ab").count());

trim/strip

assert_eq!("abc1def", "11abc1def11".trim_matches('1'));
assert_eq!("a", "  a".trim_left());
169
116
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
169
116