Skip to content

Commit 5928530

Browse files
committed
update ch10
1 parent d94b67e commit 5928530

2 files changed

Lines changed: 86 additions & 6 deletions

File tree

ch10/wcount/src/lib.rs

Lines changed: 85 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,98 @@
1+
//! `bicycle_book_wordcount` はシンプルな文字、単語、行の出現頻度の計数機能を提供します。
2+
//! 詳しくは[`count`](fn.count.html)関数のドキュメントを見て下さい。
3+
14
use regex::Regex;
25
use std::collections::HashMap;
36
use std::io::BufRead;
47

5-
pub fn count(input: impl BufRead) -> HashMap<String, usize> {
8+
/// `input` から1行ずつUTF-8文字列を読み込み、頻度を数える。
9+
///
10+
/// 頻度を数える対象はオプションによって制御される。
11+
/// * [`CountOption::Char`](enum.CountOption.html#variant.Char): Unicodeの1文字毎に頻度を数える
12+
/// * [`CountOption::Word`](enum.CountOption.html#variant.Word): 正規表現 `\w+` にマッチする単語毎に頻度を数える
13+
/// * [`CountOption::Line`](enum.CountOption.html#variant.Line): `\n`または`\r\n` で区切られた1行毎に頻度を数える
14+
///
15+
/// # Examples
16+
/// 入力中の単語の出現頻度を数える例
17+
///
18+
/// ```
19+
/// use std::io::Cursor;
20+
/// use wcount::{count, CountOption};
21+
///
22+
/// let mut input = Cursor::new("aa bb cc bb");
23+
/// let freq = count(input, CountOption::Word);
24+
///
25+
/// assert_eq!(freq["aa"], 1);
26+
/// assert_eq!(freq["bb"], 2);
27+
/// assert_eq!(freq["cc"], 1);
28+
/// ```
29+
///
30+
/// # Panics
31+
///
32+
/// 入力がUTF-8でフォーマットされていない場合にパニックする。
33+
pub fn count(input: impl BufRead, option: CountOption) -> HashMap<String, usize> {
634
let re = Regex::new(r"\w+").unwrap();
735
let mut freqs = HashMap::new(); // HashMap<String, usize>型
836

937
for line in input.lines() {
1038
let line = line.unwrap();
11-
for m in re.find_iter(&line) {
12-
let word = m.as_str().to_string();
13-
// 5. 出現した単語の出現頻度を数える
14-
*freqs.entry(word).or_insert(0) += 1;
39+
use crate::CountOption::*;
40+
match option {
41+
Char => {
42+
for c in line.chars() {
43+
*freqs.entry(c.to_string()).or_insert(0) += 1;
44+
}
45+
}
46+
Word => {
47+
for m in re.find_iter(&line) {
48+
let word = m.as_str().to_string();
49+
// 5. 出現した単語の出現頻度を数える
50+
*freqs.entry(word).or_insert(0) += 1;
51+
}
52+
}
53+
Line => *freqs.entry(line.to_string()).or_insert(0) += 1,
1554
}
1655
}
1756
freqs
1857
}
58+
59+
/// [`count`](fn.count.html)で使うオプション
60+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
61+
pub enum CountOption {
62+
/// 文字毎に頻度を数える
63+
Char,
64+
/// 単語毎に頻度を数える
65+
Word,
66+
/// 行毎に頻度を数える
67+
Line,
68+
}
69+
70+
/// オプションのデフォルトは [`Word`](enum.CountOption.html#variant.Word)
71+
impl Default for CountOption {
72+
fn default() -> Self {
73+
CountOption::Word
74+
}
75+
}
76+
77+
#[test]
78+
fn word_count_works() {
79+
use std::io::Cursor;
80+
81+
let mut exp = HashMap::new();
82+
exp.insert("aa".to_string(), 1);
83+
exp.insert("bb".to_string(), 2);
84+
exp.insert("cc".to_string(), 1);
85+
86+
assert_eq!(count(Cursor::new("aa bb cc bb"), CountOption::Word), exp);
87+
}
88+
#[test]
89+
fn word_count_works2() {
90+
use std::io::Cursor;
91+
92+
let mut exp = HashMap::new();
93+
exp.insert("aa".to_string(), 1);
94+
exp.insert("cc".to_string(), 1);
95+
exp.insert("dd".to_string(), 1);
96+
97+
assert_eq!(count(Cursor::new("aa cc dd"), CountOption::Word), exp);
98+
}

ch10/wcount/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ fn main() {
1313

1414
// 3. ファイルから1行ずつ読み込む
1515
// 第2引数 `Default::default` を加える
16-
let freqs = count(reader);
16+
let freqs = count(reader, Default::default());
1717
println!("{:?}", freqs);
1818
}

0 commit comments

Comments
 (0)