LoginSignup
162
112

More than 5 years have passed since last update.

文字列操作 with Rust

Last updated at Posted at 2018-09-07

Rustの文字列操作について書いていきます。随時更新。

char

文字の型です。

    let ch: char = 'a';
    assert_eq!(ch, 'a');

&str

文字列リテラルです。

    let s: &str = "hello";
    assert_eq!(s, "hello");

&がついていることから、通常は変更できません。

String

文字列の型です。

    let cs: String = "hello".to_string();
    assert_eq!(cs, String::from("hello"));

文字列リテラルのto_stringで文字列を取得できます。

文字列の結合

文字列の結合には、format!マクロが使えます。

    let hello: String = "hello".to_string();
    let world: String = "world".to_string();
    assert_eq!(String::from("helloworld"), format!("{}{}", hello, world));

左側がStringで右側が&strの場合、+演算子でも結合できます。

    let hello: String = "hello".to_string();
    let world: &str = "world";
    assert_eq!(String::from("helloworld"), hello + world)

一文字ずつ取得

一文字ずつ取得するには、IteratorのCharsを使います。

    let cs: String = "hello".to_string();
    for i in cs.as_str().chars() {
        println!("{}", i);
    }
結果
h
e
l
l
o

また、collectでVecにもできます。

    let v: Vec<char> = "hello".chars().collect();
    println!("{}", v[0]);
結果
h

nthも使えます。

    let v: char = "hello".chars().nth(0).unwrap();
    println!("{}", v);
結果
h

Iteratorのnextで一文字進めることができます。

    let s: &str = "hello";
    let mut chs = s.chars();
    assert_eq!(Some('h'), chs.next());
    assert_eq!(Some('e'), chs.next());
    assert_eq!(Some('l'), chs.next());
    assert_eq!(Some('l'), chs.next());
    assert_eq!(Some('o'), chs.next());

そのまま表示したい場合は、unwrapで値を取り出してください。

末尾に追加

pushでchar、push_strで&strをそれぞれStringの末尾に追加できます。

    let mut cs: String = "hello".to_string();
    cs.push(',');
    cs.push_str(" world");
    assert_eq!(String::from("hello, world"), cs);

文字列を逆順にする

revを使って文字列を逆順にします。

    let s: &str = "hello";
    assert_eq!("olleh", s.chars().rev().collect::<String>());

文字を削除

popremoveでStringから文字を削除できます。
popは、最後の文字を削除し、Optionを返します。
Stringが空だった場合、Noneを返します。

    let mut cs: String = "hello".to_string();
    assert_eq!(Some('o'), cs.pop());
    assert_eq!(Some('l'), cs.pop());
    assert_eq!(Some('l'), cs.pop());
    assert_eq!(String::from("he"), cs);

removeは、指定した位置の文字を削除して返します。

    let mut cs: String = "hello".to_string();
    assert_eq!('o', cs.remove(4));
    assert_eq!('h', cs.remove(0));
    assert_eq!(String::from("ell"), cs);

特定の文字を排除する

retainでStringの指定された文字だけを保持できます。

    let mut cs: String = "h_e_l_l_o".to_string();
    cs.retain(|c| c != '_');
    assert_eq!(String::from("hello"), cs);

文字列の大きさ

lenで取得できます。

    let cs: String = "hello".to_string();
    assert_eq!(5, cs.len());

文字列の繰り返し

repeatを使うと文字列を繰り返すことができます。

    let cs: String = "hello".to_string();
    assert_eq!(String::from("hellohellohello"), cs.repeat(3));

大文字、小文字

小文字にしたいときはto_lowercase、大文字にしたいときはto_uppercaseを使います。

    let cs: String = "hElLo".to_string();
    assert_eq!(String::from("HELLO"), cs.to_uppercase());
    assert_eq!(String::from("hello"), cs.to_lowercase());

置き換え

replacereplacenで置き換えができます。
replaceは通常の置き換えで、replacenは数を指定しての置き換えです。

    let s: &str = "foo foo foo";
    assert_eq!("faa faa faa", s.replace("o", "a"));
    assert_eq!("fee fee foo", s.replacen("o", "e", 4));

分割

文字列の分割にはsplitrsplitが使えます。

splitはパターンに一致する文字で区切ります。

    let v: Vec<&str> = "hello,world,goodbye,world".split(',').collect();
    assert_eq!(v, ["hello", "world", "goodbye", "world"]);

rsplitsplitの逆順で区切っていきます。

    let v: Vec<&str> = "hello,world,goodbye,world".rsplit(',').collect();
    assert_eq!(v, ["world", "goodbye", "world", "hello"]);

空白で分割するときは、split_whitespaceが便利です。

    let mut spw = "a   b  c d".split_whitespace();
    assert_eq!(Some("a"), spw.next());
    assert_eq!(Some("b"), spw.next());
    assert_eq!(Some("c"), spw.next());
    assert_eq!(Some("d"), spw.next());

数を指定しての分割は、splitnrsplitnで行います。

パターンを抽出する

matchesrmatchesが使えます。

    let v: Vec<&str> = "aaaOOOaaaQQQaaa".matches("aaa").collect();
    assert_eq!(v, ["aaa", "aaa", "aaa"]);
    let nv: Vec<&str> = "1aaa2bbb3ccc4".matches(char::is_numeric).collect();
    assert_eq!(nv, ["1", "2", "3", "4"]);

rmacthesmatchesの逆順です。

    let v: Vec<&str> = "aaaOOOaaaQQQaaa".rmatches("aaa").collect();
    assert_eq!(v, ["aaa", "aaa", "aaa"]);
    let nv: Vec<&str> = "1aaa2bbb3ccc4".rmatches(char::is_numeric).collect();
    assert_eq!(nv, ["4", "3", "2", "1"]);

先頭の文字列と末尾の文字列のパターン

starts_withends_withで先頭と末尾の文字列を判定できます。

    let s: &str = "hello";
    assert!(s.starts_with("he"));
    assert!(s.ends_with("lo"));

検索

findrfindで検索できます。

    let s: &str = "hello, world";
    assert_eq!(Some(0), s.find('h'));
    assert_eq!(Some(7), s.find("world"));
    assert_eq!(Some(6), s.find(char::is_whitespace));

rfindはfindの逆順です。

数字だけを抽出する

split_whitespacefilter_mapを使って数字だけを抽出します。

    let s: &str = "1 2 a 3 b 4 aaa 5 l 10";
    let cs: Vec<i32> = s.split_whitespace().filter_map(|k| k.parse().ok()).collect::<Vec<i32>>();
    assert_eq!(cs, [1, 2, 3, 4, 5, 10]);

split_whitespaceで区切り、filter_mapで数字へのパースが成功したもののみをcollectしています。

おまけ 言語処理100本ノック

言語処理100本ノックを少し解いていきます。

00
文字列"stressed"の文字を逆に(末尾から先頭に向かって)並べた文字列を得よ.

    let s: String = "stressed".chars().rev().collect::<String>();

01
「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ.

    let cs: String = "パタトクカシーー".chars().step_by(2).collect::<String>();

02
"Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."という文を単語に分解し,各単語の(アルファベットの)文字数を先頭から出現順に並べたリストを作成せよ.

    let s: &str = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.";
    let pi: Vec<usize> = s.split_whitespace()
        .map(|st| st.chars().filter(|ch| ch.is_alphabetic()).collect::<String>().len())
        .collect::<Vec<usize>>();

03
"Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."という文を単語に分解し,1, 5, 6, 7, 8, 9, 15, 16, 19番目の単語は先頭の1文字,それ以外の単語は先頭に2文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.

    let s: &str = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can.";
    let cs: Vec<String> = s.split_whitespace()
        .map(|st| st.chars().filter(|ch| ch.is_alphabetic()).collect::<String>())
        .collect::<Vec<String>>();
    let mut elem = HashMap::new();
    for (c, j) in cs.into_iter().enumerate() {
        match c {
            0 | 4...8 | 14 | 15 | 18 => {
                elem.insert(j.get(..1).unwrap().to_string(), c);
            },
            _ => { 
                elem.insert(j.get(..2).unwrap().to_string(), c);
            }
        }
    }
162
112
0

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
162
112