Rust:部分文字列の取得
ググってもクソみたいな解説しか見つからないのでここに書く。
ASCIIのみと分かっている場合は、単純なスライスを作ればよい。(Stringと&strのどちらでも同じ)
code:rs
fn main() {
let text = "ABCDEFG";
println!("{}", s); // -> CDE
}
String (または &str) の中身は UTF-8 になっていて、バイト単位で格納されている。
インデックス番号はこのバイト位置を示している。
Unicodeのコードポイント(char)として中途半端な場所、範囲を読み出そうとするとエラーになる。
(書記素の分解までは検知しない)
コードポイント単位で分割する場合は chars() で char 単位のイテレータを取り出して、skip(n) で先頭の余計なn文字を読み飛ばし、take(m) で必要なm文字を取り出し、collect() で1つにまとめて String 型にする。
code:rs
fn main() {
let text = "🍣🍺大好き💖💖";
let s = text.chars().skip(2).take(3).collect::<String>();
println!("{}", s); // -> 大好き
}
頻繁にこの処理が行われる場合
code:rust
fn main() {
let text = "🍣🍺大好き💖💖";
let cs = text.chars().collect::<Vec<_>>(); // 先に分解してしまう
let s: String = String::from_iter(&cs2..5); // let s: String = &cs2..5.iter().collect(); // たぶんこちらは遅い(未測定) println!("{}", s); // -> 大好き
}
code:rust
use unicode_segmentation::UnicodeSegmentation;
fn main() {
let text = "กำ🤷🏽♀️กำ🤷🏽♀️กำ🤷🏽♀️กำ";
let s = text.graphemes(true).skip(2).take(3).collect::<Vec<_>>().join(""); // Vec<&str> になってるのをjoinで結合
println!("{}", s); // -> กำ🤷🏽♀️กำ
}
code:rs
use unicode_segmentation::UnicodeSegmentation;
fn main() {
let text = "กำ🤷🏽♀️กำ🤷🏽♀️กำ🤷🏽♀️กำ";
let cs = text.graphemes(true).collect::<Vec<_>>();
println!("{}", s); // -> กำ🤷🏽♀️กำ
}
関連
参考
書記素で分割する方法
Rustで文字列の先頭文字や部分文字列を取得する
いわゆる素人解説になってて動くには動くが望ましくない
Rustで文字列イテレータを連結するときに便利な itertools::join は結構遅い
StringInfo と TextElementEnumerator は現在 UAX29 に準拠する