はじめに
ストレス解消にRustでプログラミング言語でも作ってみようと思ったのだが、文字列と標準入力とファイルから統一的な方法でcharを読み込むのが面倒くさく感じた。
仕方がないので、char_streamというクレートをでっち上げてみた。
使い方
初期設定
Cargo.tomlファイルに次の行を追加。
[dependencies]
char_stream = "*"
ざっくりとした流れ
基本的には、CharStreamのオブジェクトを作成したら、next()
あるいはread_line()
を呼んで1文字(あるいは1行)ずつ処理する流れ。
その他に、1文字先読みするpeek()
メソッドもある。
標準入力
標準入力から読み込む場合は、from_stdin
メソッドを使う。
extern crate char_stream;
use char_stream::CharStream;
fn main() {
let mut stream = CharStream::from_stdin();
while let Some(ch) = stream.next() {
println!("ch: {}", ch);
}
}
File
Fileから読むこむときはfrom_file
メソッドを使う。
extern crate char_stream;
use std::fs;
use char_stream::CharStream;
fn main(){
let mut f = fs::File::open("testdata.txt").unwrap();
let mut stream = CharStream::from_file(f);
// なんか処理
}
文字列(str)
文字列(str)のときはfrom
メソッド。
use char_stream::CharStream;
fn main(){
let mut stream = CharStream::from("Hello 世界❤");
// なんか処理
}
その他
Stringの場合はfrom_string
、バイト列の場合はfrom_bytes
が用意してあります。
(文字列として意味のないバイト列を食わせたときの動作保証は無し)
Iterator
CharStreamはIteratorトレイトを実装しているので、Iteratorトレイトがデフォルトで提供しているメソッドも呼べる。
例えば、
extern crate char_stream;
use char_stream::CharStream;
fn main() {
let stream = CharStream::from("Hello 世界❤");
if let Some(c) = stream.max() {
println!("max char: {}", c);
}
}
のようなコードで、(意味はないけど)文字コードが最大になる文字を求めることができる。
DoubleEndedIterator
Version0.1.1から文字列(strあるいはString)から生成したCharStreamに関してのみ、DoubleEndedIteratorトレイトへ変換可能になった。
Version0.1.5から、StdInから作成したものを除いたすべてのCharStreamから、DoubleEndedIteratorトレイトに変換可能になった。
(ただし、Fileから作成したものを変換するときには、ファイルの中身を一気にすべて読み込むので注意。この読み込みはwend_iter
を呼び出した時に起きる。)
変換にはwend_iter()
を使う。
これにより下記コードのように、逆順を求めることなどが可能になった。
(問題は言語処理100本ノック 2015を参考にした。)
extern crate char_stream;
use char_stream::CharStream;
fn main() {
let input = "stressed";
let stream = CharStream::from(input);
let rev_stream = stream.wend_iter().rev();
let result: String = rev_stream.collect();
println!("'{}' reverse to '{}'", input , result);
}
Example
標準入力から1行ずつ読み込む
extern crate char_stream;
use char_stream::CharStream;
fn main(){
let mut stream = CharStream::from_stdin();
while let Some(line) = stream.read_line() {
println!("line: '{}'", line);
}
}
ファイルの中身をひっくり返す
extern crate char_stream;
use std::fs::File;
use char_stream::CharStream;
fn main(){
let f = File::open("Cargo.toml").unwrap();
let file_stream = CharStream::from_file(f);
let stream = file_stream.wend_iter().rev();
let result: String = stream.collect();
println!("{}", result);
}