NLP100ノック第2章
第2章を一通り終えたので書きます。
10. 行数のカウント
タイトルのままです。 Rust
では std::str::Lines
で count()
がありますので利用しておわりです。
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
fn main() {
let mut args = env::args();
args.next();
for path in args {
let f = File::open(path).unwrap();
let br = BufReader::new(f);
println!("{}", br.lines().count());
}
}
11. タブをスペースに置換
コチラも、std::string::String.replace()
利用するだけです。
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
fn main() {
let mut args = env::args();
args.next();
for path in args {
let file = File::open(path).unwrap();
let reader = BufReader::new(file);
for line in reader.lines() {
println!("{}", line.unwrap().replace("\t", " "));
}
}
}
12. 1列目をcol1.txtに,2列目をcol2.txtに保存
こちらは単純にファイルに書き込むのと、分割ができれば問題ないです。
use std::env;
use std::fs::File;
use std::io::{BufReader, BufWriter, Write};
use std::io::prelude::*;
fn main() {
let mut args = env::args();
args.next();
for path in args {
let f = path.clone().replace(".txt", "");
let s = path.clone().replace(".txt", "");
let file = File::open(path).unwrap();
let br = BufReader::new(file);
let mut first_column = BufWriter::new(File::create(format!("{}_col1.txt", f)).unwrap());
let mut second_column = BufWriter::new(File::create(format!("{}_col2.txt", s)).unwrap());
for line in br.lines() {
let words = line.unwrap().split("\t").map(|m| m.to_string()).collect::<Vec<String>>();
first_column.write(format!("{}\n", words[0]).as_bytes()).unwrap();
second_column.write(format!("{}\n", words[1]).as_bytes()).unwrap();
}
}
}
13. col1.txtとcol2.txtをマージ
こちらは以前利用した、zip
があれば問題ないです。
use std::env;
use std::fs::File;
use std::io::{BufReader, BufWriter, Write};
use std::io::prelude::*;
fn main() {
let mut args = env::args();
if args.len() < 2 { panic!("col1.txt col2.txt"); }
args.next();
let first = args.next().unwrap();
let second = args.next().unwrap();
let fr = BufReader::new(File::open(first).unwrap()).lines().map(|m| m.unwrap().to_string()).collect::<Vec<String>>();
let sr = BufReader::new(File::open(second).unwrap()).lines().map(|m| m.unwrap().to_string()).collect::<Vec<String>>();
let mut merge_file =
BufWriter::new(File::create("merge.txt".to_string()).unwrap());
for (x, y) in fr.iter().zip(&sr) {
merge_file.write(format!("{}\t{}\n", x, y).as_bytes()).unwrap();
}
}
14. 先頭からN行を出力
head
コマンドですので std::iter::Iterator.take()
を利用するだけです。
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
fn main() {
let args = env::args().skip(1).collect::<Vec<String>>();
let file = File::open(&args[0]).unwrap();
let br = BufReader::new(file).lines().take((&args[1]).to_string().parse::<usize>().unwrap());
for line in br.map(|m| m.unwrap().to_string()).collect::<Vec<String>>() {
println!("{}", line);
}
}
15. 末尾のN行を出力
tail
コマンドです。こちらは std::iter::Iterator.skip()
を利用してやるだけです。
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
fn main() {
let args = env::args().skip(1).collect::<Vec<String>>();
let file = File::open(&args[0]).unwrap();
let takes = (&args[1]).to_string().parse::<usize>().unwrap();
let br = BufReader::new(&file).lines();
let skips = br.count() - takes;
let file = File::open(&args[0]).unwrap();
let lines = BufReader::new(&file).lines().skip(skips);
for line in lines {
println!("{}", line.unwrap());
}
}
16. ファイルをN分割する
こちらの実装は素朴な実装とし、行数で分割しております。
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::BufWriter;
use std::io::prelude::*;
fn main() {
let args: Vec<String> = env::args().skip(1).collect();
let path = &args[0].to_string();
let file = File::open(path).unwrap();
let count: usize = BufReader::new(file).lines().count();
let div: usize = (&args[1]).to_string().parse().unwrap();
let file = File::open(path).unwrap();
let mut br = BufReader::new(file).lines();
let t = (count as f64/ div as f64).ceil() as usize;
for x in 1 .. div + 1 {
let l = br.by_ref();
let file = File::create(format!("{}.txt",x)).unwrap();
let mut bw = BufWriter::new(file);
for y in l.take(t).map(|m| m.unwrap().to_string()).collect::<Vec<String>>() {
let a = format!("{}\n", y);
bw.write(a.as_bytes()).unwrap();
println!("{}: {}", x, y);
}
}
}
17. 1列目の文字列の異なり
ファイル読込 + HashSet
で実装
use std::collections::HashSet;
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
extern crate regex;
use regex::Regex;
fn main() {
let args: Vec<String> = env::args().skip(1).collect();
let path = &args[0].to_string();
let file = File::open(path).unwrap();
let re = Regex::new(r"\W+").unwrap();
let hs = BufReader::new(file).lines().map(|m|{
let l = m.unwrap().clone();
re.split(&l).next().unwrap().to_string()
}).collect::<HashSet<_>>();
for s in hs {
println!("{}", s);
}
}
18. 各行を3コラム目の数値の降順にソート
こちら、実数の比較を行う必要があり、すこし めんどう でした。
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
fn main() {
let args: Vec<String> = env::args().skip(1).collect();
let path = &args[0].to_string();
let file = File::open(path).unwrap();
let mut val = BufReader::new(file).lines().map(|m| m.unwrap().split("\t").skip(2).next().unwrap().parse::<f64>().unwrap()).collect::<Vec<f64>>();
val.sort_by(|a, b| a.partial_cmp(b).unwrap());
for v in val { println!("{}", v); }
}
19. 各行の1コラム目の文字列の出現頻度を求め,出現頻度の高い順に並べる
18の問題を更にカウントできるように変更した。
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
enum Value {
USIZE(usize),
NONE(()),
}
fn main() {
let args = env::args().skip(1).collect::<Vec<String>>();
let file = File::open(&args[0]).unwrap();
let mut words: HashMap<String, usize> = HashMap::new();
for m in BufReader::new(&file).lines() {
let w = m.unwrap().to_string().split("\t").next().unwrap().to_string();
let v = match words.get(&w) {
None => 1,
Some(n) => n + 1,
};
words.insert(w, v);
}
let mut vars: Vec<(&String, &usize)> = words.iter().collect();
vars.sort_by(|a, b| b.1.cmp(a.1));
for (w, v) in vars {println!("{}: {}", w, v);}
}
おわり
この章は慣れてきたのか比較的楽に解けています。