前回、言語処理100本ノック の04までやったので05からやります。

05. ngram

こいつはbi-gramを単語、文字二つを実装するひつようがあります

fn bigram(words: Vec<String>) -> Vec<String> {
    let mut bi: Vec<String> = Vec::new();
    let mut i = 0;

    loop {
        let w = i + 2;
        if w > words.len() { break; }
        bi.push(words[i..w].join(""));
        i += 1;
    }
    bi
}

fn main() {
    let words = "I am an NLPer".split(' ').map(|m| m.to_string()).collect::<Vec<String>>();
    println!("\n===word bi-gram");
    for word in bigram(words) {
        println!("{}", word);
    }

    let words = "I am an NLPer".chars().map(|m| m.to_string()).collect::<Vec<String>>();
    for word in bigram(words) {
        println!("\"{}\"", word);
    }

}

06. 集合

これは単純に HashSet を利用して、解決します。HashSet の差集合は difference を利用し、和集合は union を、積集合は intersection をそれぞれ利用します。また、特定の要素が含有していることを判定するには contains を利用して判定します。

use std::collections::HashSet;

fn bigram(words: Vec<String>) -> HashSet<String> {
    let mut bi: HashSet<String> = HashSet::new();
    let mut i = 0;

    loop {
        let w = i + 2;
        if w > words.len() { break; }
        bi.insert(words[i..w].join(""));
        i += 1;
    }
    bi
}

fn chars(s: String) -> Vec<String> {
    s.chars().map(|m| m.to_string()).collect::<Vec<String>>()
}

fn main() {
    let s1 = bigram(chars("paraparaparadise".to_string()));
    let s2 = bigram(chars("paragraph".to_string()));

    println!("===UNION===");
    for x in s1.union(&s2) {
        println!("{}", x);
    }

    println!("\n===DIFF===");
    println!("===s1 - s2===");
    for x in s1.difference(&s2) {
        println!("{}", x);
    }
    println!("===s2 - s1===");
    for x in s2.difference(&s1) {
        println!("{}", x);
    }

    println!("\n===intersection===");
    for x in s1.intersection(&s2) {
        println!("{}", x);
    }

    println!("\n===INCLUDE===");
    let se = "se";
    println!("s1: {}", s1.contains(se));
    println!("s2: {}", s2.contains(se));
}

07. テンプレートによる文生成

これは format! を使えば終りです。(問題意図ほんとこれなんか?)

fn string_template(x: i8, y: &str, z: f32) -> String {
    format!("{}時の{}は{}", x, y, z)
}

fn main() {
    let string = string_template(12, "気温", 22.5);
    println!("{}", string);
}

08. 暗号文

ASCII以外の判定と、小文字のASCIIが判れば簡単です。

use std::ascii::AsciiExt;

fn cipher(src: &str) -> String {
    let chars = src.chars().collect::<Vec<char>>();
    let mut result: String = String::new();
    for c in chars {
        let s = if c.is_ascii() {
            let var: u8 = c as u8;
            match var {
                97 ... 122 => (219 - (var)) as char,
                _ => c,
            }
        } else {
            c
        };
        result.push(s);
    }
    result
}

fn main() {
    println!("{}", cipher("Today is fine."));
    println!("{}", cipher(&cipher("Today is fine.")));
}

09. Typoglycemia

こちらは、 Vecshuffle 的なものがないので、rand を呼び出して shuffle を使います。

extern crate rand;
use rand::Rng;

fn words(src: &str) -> Vec<String> {
    let mut result: Vec<String> = Vec::new();

    for s in src.split(' ').collect::<Vec<&str>>() {
        let mut chars = s.chars().collect::<Vec<char>>();
        if chars.len() < 5 {
            result.push(s.to_string());
        } else {
            let last_index = chars.len() - 1;
            let first_char = chars[0];
            let last_char = chars[last_index];

            let rand_chars = &mut chars[1..last_index];
            shuffle(rand_chars);
            let mut rand_string = String::new();
            for c in rand_chars { rand_string.push(*c) }
            result.push(format!("{}{}{}", first_char, rand_string, last_char));
        }
    }
    result
}

fn shuffle(chars: &mut [char]) {
    rand::thread_rng().shuffle(chars);
}

fn main() {
    let paragraph = "I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind .";

    for w in words(paragraph) {
        println!("{}", w);
    }
}

おわり

ということで Rust で言語処理100本ノック1章をやってみました。 最近 Ruby しか書いていなかったので、新鮮で楽しいですね Rust