やりたいこと・質問
std::io::BufRead
から 1バイト(u8型)ではなく、1文字(char型)取り出したいです。エンコードはUTF-8を想定しています。
BufRead, Readを見る限りそのようなメソッドは無さそうです。
https://doc.rust-lang.org/std/io/trait.BufRead.html
検索を掛けてみましたが、定石と呼ばれるような方法は見つかりませんでした。
Rubyならば、以下のようにgetc
でできます。
ruby
1require 'stringio' 2 3StringIO.open("fooほげ") do |io| 4 while !io.eof? 5 puts io.getc 6 end 7end
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
ベストアンサー
UTF-8 文字列から一文字ずつ取り出すための API として str::chars
が提供されているので,とりあえずの用途であればこれを使用するのが良いかと思います.
ただし対象となる全データを読み込む必要があるため,巨大なファイルを扱う場合などは注意する必要があります.
rust
1let mut file = io::BufReader::new(fs::File::open("/path/to/content")?); 2 3let mut content = String::new(); 4file.read_to_string(&mut content)?; 5 6for ch in content.chars() { 7 // do something 8}
ツールチェインのバージョンが 1.26 以降であれば,fs::read_to_string
を用いて次のように記述することもできます(この場合も読み込むデータのサイズには注意が必要):
rust
1for ch in fs::read_to_string("/path/to/content")?.chars() { 2 // do something 3}
かつて io::Read
にも一文字ずつ読み込むための chars
が存在していましたが(当時の API ドキュメント),このメソッドは残念ながら 1.27 から廃止されており現在では使用することができません(いずれにせよ unstable でしたが...)
投稿2019/06/22 05:37
編集2019/06/22 05:44総合スコア58
0
既に回答がついていますが、補足を。
現状1字づつ取り出す手段がないので回答のように一旦全部の文字列を読み出すことになるでしょう。
メモリ使用量が気になるなら 一旦lines
で取り出してから読むこともできます。
rust
1use std::io::{self, prelude::*}; 2 3fn main() -> io::Result<()> { 4 let input = io::Cursor::new("椿榎楸柊".bytes().collect::<Vec<u8>>()); 5 for line in input.lines() { 6 for c in line?.chars() { 7 println!("{}", c); 8 } 9 } 10 Ok(()) 11} 12
もしどうしても1文字づつがいいなら from_utf8
を使ってUTF-8をデコードしつつ読み出す方法もありますが少し大変です。
rust
1use std::io::{self, prelude::*}; 2use std::str::from_utf8; 3 4struct Getc<R> { 5 input: io::Bytes<R>, 6} 7 8impl<R> Getc<R> 9where 10 R: Read, 11{ 12 fn from_reader(input: R) -> Self { 13 Self { 14 input: input.bytes(), 15 } 16 } 17} 18 19impl<R> Iterator for Getc<R> 20where 21 R: Read, 22{ 23 type Item = io::Result<char>; 24 fn next(&mut self) -> Option<io::Result<char>> { 25 // UTF-8なので最大3バイト読めばよい 26 let mut buf = [0u8; 3]; 27 for i in 0..3 { 28 match self.input.next() { 29 None => return None, 30 Some(Err(e)) => return Some(Err(e)), 31 Some(Ok(b)) => { 32 buf[i] = b; 33 // 今まで読んだバイトを文字列として解釈できるならその最初の文字を取り出す 34 match from_utf8(&buf[0..=i]) { 35 Ok(s) => return s.chars().next().map(Ok), 36 Err(_) => continue, 37 } 38 } 39 } 40 } 41 // non utf-8 42 Some(Err(io::ErrorKind::InvalidData.into())) 43 } 44} 45 46fn main() { 47 let mut input = io::Cursor::new("椿榎楸柊".bytes().collect::<Vec<u8>>()); 48 for c in Getc::from_reader(&mut input) { 49 println!("{:?}", c) 50 } 51} 52
投稿2019/06/22 06:12
総合スコア468
0
2バイト読み込んだらchar型に変換すれば良いのではないでしょうか。
変換についてはこちらの記事をご参考下さい。
https://qiita.com/chezou/items/947900faef4c1032ed94
投稿2019/06/22 04:35
総合スコア702
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/06/22 04:40
2019/06/22 04:51
2019/06/22 04:57
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/06/22 06:08