質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

Q&A

解決済

3回答

3162閲覧

std::io::BufReadから1文字ずつ取り出す

maai

総合スコア463

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

0グッド

0クリップ

投稿2019/06/22 04:26

やりたいこと・質問

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ページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答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
ubnt-intrepid

総合スコア58

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

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

playground

もしどうしても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

playground

投稿2019/06/22 06:12

blackenedgold

総合スコア468

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

blackenedgold

2019/06/22 06:14

1文字づつ読む際の注意ですが、文字の途中でエラーになった際は読みかけのデータは揮発します。
IgaguriMK

2019/09/25 00:06

基本多言語面外の文字(典型的には人名用漢字や絵文字)が4バイトになり得るので、正しくパースするには4バイト読み込まないといけません。 逆に、5バイト以上のシーケンスはエンコード体系としては可能ではありますが、UTF-8としては不正なので4バイト読めば十分です。
guest

0

2バイト読み込んだらchar型に変換すれば良いのではないでしょうか。
変換についてはこちらの記事をご参考下さい。
https://qiita.com/chezou/items/947900faef4c1032ed94

投稿2019/06/22 04:35

marurunn

総合スコア702

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2019/06/22 04:51

ならその読み込みシーケンスで読んでいけばいいかと
marurunn

2019/06/22 04:57

であれば1バイト読み込むごとにencodeメソッドを試み、 文字化けを起こしているか確認してみてはいかがでしょうか。 デフォルトで不正なバイトがあった場合例外を投げるようになっているので、例外をキャッチした場合さらに1バイト読み込んでもう1度encodeが出来るか試す。 これを正常にエンコードされるまで繰り返せばよいかと思います。 https://docs.ruby-lang.org/ja/latest/method/String/i/encode.html
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問