鈍足ランナーのIT日記

走るのが好きな5流のITエンジニアのブログ。

趣味の範囲は広いけど、どれも中途半端なクソブロガー楽しめるWebアプリを作ってあっと言わせたい。サーバーサイドPerl(Mojolicious)、クライアントサイドVue.js。Arduinoにも触手を伸ばす予定。

地名や人名などが当て字かどうか判断したい場合のモジュールを作る

最近、日本語処理に目覚めた訳ではないけれど、親父ギャクレコメンデーションモジュールの次は漢字の読み候補を出してくれるモジュールの制作した。
kakasiを利用。当て字かどうか判断したい場合に使えると思います。

kakasiには漢字1文字1文字の読みを出力する-yオプションというのもがあり、
それを利用して、出力された結果を組み合わせして返すというものです。

kakasiコマンドを呼ぶ部分は、kakasi.jsというモジュールを流用し、その後の編集部分を加えた感じです。

以下のように使います。

var kk = new Kakasi({
    debug: false
});
kk.transliterate( "歌舞伎町" )
.then(results => {
    console.log("----------\n%s\n----------",results);
})
.catch(error => {
    console.error(error);
});

// results in yomi array うたまいきまち,かまいきまち,うたぶきまち,かぶきまち,うたまいぎまち,かまいぎまち,うたぶぎまち,かぶぎまち,うたまいわざまち,かまいわざまち,うたぶわざまち,かぶわざまち,うたまいきちょう,かまいきちょう,うたぶきちょう,かぶきちょう,うたまいぎちょう,かまいぎちょう,うたぶぎちょう,かぶぎちょう,うたまいわざちょう,かまいわざちょう,うたぶわざちょう,かぶわざちょう

参考にしたモジュール

漢字の読みを取得するkakasi.js

github.com

文字種の判定はnihongo.jsを使う

www.npmjs.com

文字種の変換はMoji.js

github.com

完成品

github.com

親父ギャクを作ってくれるモジュール

Mecabを使って、文中に出てくる最後の名詞の中の文字を似たような発音の
文字に置き換えて意味が通るもの変わったものだけを表示してくれる。

dokechin$ node test.js  いざ鎌倉
いざクラクラ
いざヤマガラ
いざカラカラ
いざカタクリ
いざカラクリ
いざカマキリ
dokechin$ node test.js 論より証拠
論よりショート
論よりジョーク
論よりチョーク
dokechin$ node test.js 猫に小判
猫にカバン
猫にロビン
猫にカカン
猫にガタン
猫にトタン
猫にガマン
猫にロマン
猫にカラン

github.com

温度によって、ダイキンエアコンを制御したい。

赤外線センサーPL-IRM2121 (38kHz)のつなぎ方

qiita.com
ダイキンエアコンは101バイト超以上のコードが出力されているので、下記ブログの
ダンパーを使用して見ました。
hawksnowlog.blogspot.com

赤外線LEDの電流制限抵抗

5mm赤外線LED 945nm SLR-938CV-Aというものを秋月で購入。
1.3V 50mAの赤外線LEDに入れる抵抗値
5-1.3/0.05=74Ω

制御できないす。

扇風機は制御できたのですが、エアコンはうまくできませんでした。
色々と信号が行き来しているかもしれないし。LEDの出力が足りないかもしれない。

デジタル3番ピン

40mAしか、電流が取り出せない。波のある出力なので、(1/3換算するとして)赤外線LEDを駆動するには若干非力かも。
トランジスタの増幅回路を組む必要があるようなので2N5088というのを使っている回路で勉強。
再度秋月で購入。もっと下調べしないとダメだなぁ。送料が・・
www.pinterest.co.uk

トランジスタ入れて見たが

増幅しようとトランジスタ入れて見たが・・LEDが壊れてしまったようです。

他にもサインを計測する方法が

mag.switch-science.com

4009.jp

もうダメか・・

再度LED注文中。。

そんな感じです。

やっぱり動かない。

信号が、上手く再現されていないんだろうなぁ。

mixi.jp

qiita.com

今流行のAIではない俳句ジェネレーター。「俳人さん」のアルゴリズムの全貌

https://haijinsan.dokechin.com/

適当なアルゴリズムの全貌を紹介。

上五

現在月から適当に季語のリストの中からランダムに選ぶ。

function getKami(){
    var date = new Date();
    var month = date.getMonth();
    var kamis = [];

    if (month == 0 ) {
        kamis.push("新年の", "寒月の");
    } else if ( month == 1) {
        kamis.push("梅が香に", "寒明し");
    } else if ( month == 2) {
        kamis.push("暖かき", "啓蟄の");
    } else if ( month == 3) {
        kamis.push("清明の", "春眠の");
    } else if ( month == 4) {
        kamis.push("薫風の", "夏めくや");
    } else if ( month == 5) {
        kamis.push("夏至の日に", "六月の");
    } else if ( month == 6) {
        kamis.push("七月の", "梅雨明けや");
    } else if ( month == 7) {
        kamis.push("八月の", "真夏日の");
    } else if ( month == 8) {
        kamis.push("長月の", "夏彼岸");
    } else if ( month == 9) {
        kamis.push("十月の", "秋の日の");
    } else if ( month == 10) {
        kamis.push("霜月の", "落ち葉降る");
    } else if ( month == 11) {
        kamis.push("数え日の", "十二月");
    }   
    index = Math.floor(Math.random() * 2)
    return kamis[index];
}

中七

Azure Vision APIに画像を投げて、画像を要約した日本語を取得。Yahoo 形態素APIに投げて、
形容詞+名詞の部分を抽出して中7とする。形容詞だったら1、名詞だったら7とマッピングしておいて正規表現17でサーチをかけるようにした。

「白い新聞」のように7文字なら、そのまま。
「白い水菜」のように6文字なら、「よ」を後ろに足して、「白い水菜よ」にして7文字とする。
「白いシャツ」のように5文字なら、「その」を前に足して、「その白いシャツ」にして7文字とする。
「白い酢」のように4文字なら、「その」を前に足して、「や」を後ろに足して、「その白い酢や」にして7文字とする。

形容詞+名詞がなかったら、「今日思い入る」と入れる。
形容詞+名詞が複数あったら、ランダムで選択する。

座五

Azure Vision APIの結果で、タグが配列で帰るので、Yahoo形態素APIに配列を文字列に展開して、呼び出し。
形容詞だけにフィルタリング。「若い」のように末尾の「い」を「さ」に変える。

3文字だったら「かな」を足して、5文字にする。例。「若さかな」
5文字だったら。そのまま代入。「美しい」→「美しい」

形容詞がなかったら、「朝ぼらけかな」にする。
形容詞が複数あったら、ランダムで選択する。

async await

Azure Vision APIとYahoo形態素APIは共にAxiosで呼び出し。promise baseなAPIとなっている。
Yahoo形態素APIの結果はxmlが帰ってくる、xmlだと扱いが面倒なので、jsonへ変換。
変換部分はxml-to-json-promiseモジュールを利用。これもpromise baseなAPIとなっている。
全部promisebaseに寄せれば、async awaitを利用できて、スッキリ書ける。
async functionも非同期なので、promiseベースなんだなぁと発見した。

Parserについて勉強したい

Bool用Parserに変えて見る

下記のような真偽値をパースするパーサを作って見る。

1 | 1 & 0

ほぼ、元の四則演算そのものなんですが・・
&の優先順位が|よりも高いので、除算のところを&にして、加算のところを|にして見ました。
あとは0の扱いに注意が必要でundefだとエラーにしました。
計算する部分も実装して見ました。

use 5.018000;

package Calc {
    use Carp ();

    sub parse {
        local $_ = $_[1];

        _parse_expr();
    }

    sub err {
        my ($msg) = @_;
        my $ret = join('',
            $_, "\n",
            (" " x pos()) . "^\n",
            $msg, "\n",
        );
        Carp::croak $ret;
    }

    sub _parse_expr {
        my @nodes;
        until (/\G\s*\z/gc) {
            my $m = _parse_add()
                or do {
                err "Syntax error";
            };
            push @nodes, $m;
        }
        return ['expr', @nodes];
    }

    sub _parse_add {
        my $mul = _parse_mul()
            or return undef;
        while (m{\G\s*(\|)}gc) {
            my $op = $1;
            my $lhs = _parse_mul()
                // die "Cannot parse mul after '$op' : " . pos();
            $mul = [$op, $mul, $lhs];
        }
        return $mul;
    }

    sub _parse_mul {
        my $node = _parse_term()
            // return undef;
        while (m{\G\s*(\&)}gc) {
            my $op = $1;
            my $lhs = _parse_term() // 
                die "Cannot parse expr after '$op' : " . pos();
            $node = [$op, $node, $lhs];
        }
        return $node;
    }

    sub _parse_term {
        if (/\G\s*([01])/gc) {
            return $1;
        } elsif (/\G\s*\(/gc) {
            my $expr = _parse_add();
            /\G\s*\)/gc
                or err "No closing paren after opening paren.";
            return $expr;
        }
        return undef;
    }

    sub execute {
        $DB::single = 1;
        my $node = $_[1][1];
        if (ref($node)) {
            return _execute($node);
        } else {
            return $node;
        }
    }

    sub _execute {
        my $node = shift;
        my $ope = $node->[0];
        my $left = $node->[1];
        my $right = $node->[2];
        if (ref($right)) {
            my $right = _execute( $right );
        }
        if ( $ope eq "&" ) {
            if ( $left == 1 && $right == 1 ) {
                return 1;
            }
            return 0;
        } else {
            if ( $left == 1 || $right == 1 ) {
                return 1;
            }
            return 0;
        }
    }
}

my $node = Calc->parse('1|1&0');
use Data::Dumper; warn Dumper($node);
warn Calc->execute($node);