Rust 入門 簡単な関数を書いてみる(4)

Rust入門の続き

住所から都道府県と市区町村を抜き出す関数はできたので、次は番地と建物を抜き出す必要があるが、その前に番地等の表記ゆれを正規化するために、漢数字をアラビア数字に変換する関数を書く。

Rust でも、PascalC#みたいに関数内関数を書けるのだな。 三項演算子と同様、経験的に使う人と使わない人がはっきり分かれる機能だと思うけど、僕は結構好んで使う方だ。

// 漢数字をアラビア数字に変換する
fn kanji_numeral_to_arabic_numerals(s: &str) -> String {

    // 漢数字を半角数字に置換する
    fn z2h(s: &str) -> String {
        s.replace("一", "1")
        .replace("壱", "1")
        .replace("1", "1")
        .replace("二", "2")
        .replace("弐", "2")
        .replace("2", "2")
        .replace("三", "3")
        .replace("参", "3")
        .replace("3", "3")
        .replace("四", "4")
        .replace("4", "4")
        .replace("五", "5")
        .replace("5", "5")
        .replace("六", "6")
        .replace("6", "6")
        .replace("七", "7")
        .replace("7", "7")
        .replace("八", "8")
        .replace("8", "8")
        .replace("九","9")
        .replace("9", "9")
        .replace("〇", "0")
        .replace("0", "0")
    };

    // 変換処理
    fn convert(s: &str, re: Regex) -> i64 {

        let mut digits: HashMap<&str, i64> = HashMap::new();
        digits.insert("十", 10);
        digits.insert("拾", 10);
        digits.insert("百", 100);
        digits.insert("千", 1000);
        digits.insert("万", 10000);
        digits.insert("億", 100000000);
        digits.insert("兆", 1000000000000);

        let reg_arabic_numerals:Regex = Regex::new("^[0-9]+$").unwrap();

        let mut unit:i64 = 1;
        let mut result:i64 = 0;
        for piece in re.find_iter(s).map(|m| m.as_str()).collect::<Vec<&str>>().iter().rev() {
            if digits.contains_key(piece) {
                if unit > 1 {
                    result += unit;
                }
                unit = digits[piece];
            } else {
                if reg_arabic_numerals.is_match(piece) {
                    result += piece.parse::<i64>().unwrap() * unit;
                } else {
                    let reg_divide_digit_unit:Regex = Regex::new("[十拾百千]|\\d+").unwrap();
                    result += convert(piece, reg_divide_digit_unit) * unit;
                };
                unit = 1;            
            }
        }
        result
    };
    
    convert(&z2h(s), Regex::new("[万億兆]|[^万億兆]+").unwrap()).to_string()
}

Rust 入門 簡単な関数を書いてみる(3)

Rust 入門つづき。

引き続き住所を正規化する関数を書きながらRustの学習を進めているのだが、なんだかまだ理解できない状況にぶつかった。

正規表現でマッチした箇所を逆順に処理したく、試行錯誤の結果とりあえず次のような記述でいけそうなトコまでは辿り着いた。

let v: Vec<&str> = re.find_iter(s).map(|m| m.as_str()).collect();
for piece in v.iter().rev() {
    // 何かしたい処理
}

しかし、こう書くと「cannot infer type for B」というコンパイルエラーになる。

for piece in re.find_iter(s).map(|m| m.as_str()).collect().iter().rev() {
  // 何かしたい処理
}

これは、

let v: = re.find_iter(s).map(|m| m.as_str()).collect();

こう書くと、結果の型推論が利かずコンパイルエラーになるのと同じ原因だと思うのだが、何故そうなるのかがまだ理解できていない。

Rust なかなか手ごわい。


追記

collect() は型ヒントで型を明示しないといけないというのを完全に忘れていた。 という訳で型を指定することで1行で書けるようになった。

for piece in re.find_iter(s).map(|m| m.as_str()).collect::<Vec<&str>>().iter().rev() {
  // 何かしたい処理
}

前に書いた、都道府県を抜き出す処理ではキチンと collect() を呼ぶときに型指定してんのに、何で忘れるかなぁ。

初めてのGraphQL

オライリーからGraphQLの入門書が出たので購入。

今やってる仕事はバックエンドをRESTにしてるけど、複雑な問い合わせ画面だとクエリストリングが長くなりすぎてエラーになるからGETは諦めてPOSTにしちゃうとか、ちょっと残念な気分になることがあるので、紹介系のAPIは GraphQLの方が向いてそうな気がしてる。

前半 は GraphQL の概説、スキーマ―の解説で、後半は JavaScript の GraphQL ライブラリである Apollo を利用して簡単な画像投稿サイトを実際に作成するチュートリアルという構成。
文章はかなり平易で読みやすい。チュートリアルの方はフロントエンドが React、バックエンドは Node.js + Express をベースにしていてそこら辺の解説はほぼないが、知識が薄くとも読む分にはとくに困ったり引っかかるようなとこはなかった。今回、手は動かしていないので写経するとなるとまた話は違うものがあるかもしれない。

GraphQLのクエリのパースなどの面倒な部分は完全に Apollo に任せる感じで、サーバーを自力で実装しなければならないとか、JavaScirpt 以外の言語で実装するといった用途には向かないかも。
仕事だとバックエンドはC#を使用することが多いので、C#用のライブラリを探してみる必要があるな。

初めてのGraphQL ―Webサービスを作って学ぶ新世代API

初めてのGraphQL ―Webサービスを作って学ぶ新世代API

www.apollographql.com

M5Stack 導入手順メモ

注文していたM5StackとUSBケーブルが届いたのでセットアップを行う。

環境は

  • 母艦:MacBook PRO 15inch 2018 (Cataline)
  • 子機:M5Stack Gray

以下のページを参考にセットアップを行う。

qiita.com

↑ページの書いてあるとおりに実行するだけで特に問題なくセットアップは完了。 一応、念の為、手順のメモを残しておく。

1. USBドライバのインストール

M5Stack の公式サイトからUSBドライバ(CP210X Driver)をダウンロードしてインストールする。

m5stack.com

ダウンロードしたZIPを解凍するとdmgが出てくるのでマウントする。中の Silicon Labs VCP Driver.pkg だおダブルクリックでインストールする。途中、セキュリティに関する警告が出るので、システム環境設定のセキュリティとプライバシーのパネルでアクセスを許可してやる必要がある。

/dev/tty.SLAB_USBtoUART

が存在すればインストールは成功。

2. ArduinoIDEのインストール

Arduinoの更新サイトからIDEをダウンロードする。

www.arduino.cc

ダウンロードしたZIPを解凍するとプログラムが出てくるので、アプリケーションフォルダにコピーする。

3. Arduino core for the ESP32 のインストール

github.com

サイトにあるドキュメント「Installation instructions for Mac OS」に従い、以下のコマンドを実行する。

mkdir -p ~/Documents/Arduino/hardware/espressif && \
cd ~/Documents/Arduino/hardware/espressif && \
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
cd esp32 && \
git submodule update --init --recursive && \
cd tools && \
python get.py 

4. ArduinoIDEの設定。

ArduinoIDEを起動して以下の設定を行う。

  1. メニュー:ツール→シリアルポートより、/dev/tty.SLAB_USBtoUART を選択。
  2. メニュー:ツール→ボードより、M5Stack-Core-ESP32 を選択。
  3. メニュー:スケッチ→ライブラリをインクルード→ライブラリを管理を選択。
  4. 表示されるライブラリマネージャーのダイアログより、M5Stack用のライブラリ「M5Stack by M5Stack」をインストールする。

5.Hello Worldの実行

テストに、サンプルで用意されている Hello World をM5Stackに転送・実行してみる。

  1. M5StackをUSBケーブルでMacに接続。
  2. M5Stackの電源をON
  3. ArduinoIDEで、メニュー:ファイル→スケッチ例→M5Stack→Basic→Hello World を選択。
  4. 開かれたスケッチの「マイコンボードに書き込む」ボタンをクリック。
  5. スケッチがコンパイルされてM5Stackに転送後、再起動して Hellow World が液晶パネルに表示される。 f:id:tricogimmick:20191110134227j:plain

とりあえず動作確認までOK。

Rust 入門 簡単な関数を書いてみる(2)

Rust 入門つづき。

前回、簡単な関数のサンプルとして住所から都道府県を切り出すトコロを書いたので、次は市区町村を切り出す関数。

その前に、前回は関数の戻り値として Option を返すようにしていたのだが、良く考えるとあまり意味がなく冗長なだけなので、単純にタプルを返すように修正。 今回作成する市区町村を切り出す関数も同様の仕様とする。

とりあえず、以前に書いたC#のコードを元に書いてはみたが、変数 re2 を用いた正規表現のチェックを2か所でやってるのがイマイチ。何か巧いやり方はないものか。

Rust の String と &str の使い分けは初学者にはややこしい。イメージとしては String は一般的な文字列型、&str は文字列のスライスと(今のところ)理解していて、 関数の引数には &str で戻り値には String ぐらいのザックリとした感覚で書いている。(最初、&str を戻り値で返そうとしたら怒られた)

今回、ちょっと引っかかったのは、

let city: &str;
if let Some(m) = re.captures(address) {
  city = &m[1]
}

というような感じのコードを書いたら

borrowed value does not live long enoughrustc(E0597)

と怒られたことで、変数mの値はif文のブロックを抜けた時点で破棄されるため、参照をブロックの外に持ち出しちゃダメよということらしい。
当たり前のことだが、まだ身についてないのでついついこういうしょーもないミスをしてしまう。

extern crate regex;
use regex::Regex;

const PREFECTURES:[(&str, &str); 47] = [
        ("01","北海道"), ("02","青森県"), ("03","岩手県"), ("04","宮城県"), ("05","秋田県"),
        ("06","山形県"), ("07","福島県"), ("08","茨城県"), ("09","栃木県"), ("10","群馬県"),
        ("11","埼玉県"), ("12","千葉県"), ("13","東京都"), ("14","神奈川県"), ("15","新潟県"),
        ("16","富山県"), ("17","石川県"), ("18","福井県"), ("19","山梨県"), ("20","長野県"),
        ("21","岐阜県"), ("22","静岡県"), ("23","愛知県"), ("24","三重県"), ("25","滋賀県"),
        ("26","京都府"), ("27","大阪府"), ("28","兵庫県"), ("29","奈良県"), ("30","和歌山県"),
        ("31","鳥取県"), ("32","島根県"), ("33","岡山県"), ("34","広島県"), ("35","山口県"),
        ("36","徳島県"), ("37","香川県"), ("38","愛媛県"), ("39","高知県"), ("40","福岡県"),
        ("41","佐賀県"), ("42","長崎県"), ("43","熊本県"), ("44","大分県"), ("45","宮崎県"),
        ("46","鹿児島県"), ("47","沖縄県")    
    ];

// 住所から都道府県とそれ以降を分割する
fn get_prefecture(address: &str) -> (String, String) {
    let prefectures = PREFECTURES.iter().map(|x| x.1).collect::<Vec<&str>>().join("|");
    let pattern = format!("^({})(.+*)$", prefectures);
    let re = Regex::new(&pattern).unwrap();

    match re.captures(address) {
        Some(m) => ((&m[1]).to_string(), (&m[2]).to_string()),
        None => ("".to_string(), address.to_string())
    }
}

// 住所から市区町村とそれ以降を分割する
fn get_city(address: &str) -> (String, String) {
    let re1 = Regex::new(concat!(
        "^(余市郡(仁木町|赤井川村|余市町)|余市町|柴田郡村田町|(武蔵|東)村山市|",
        "[東西北]村山郡...?町|田村(市|郡..町)芳賀郡市貝町|(佐波郡)?玉村町|[羽大]村市|",
        "(十日|大)町市|(中新川郡)?上市町|(野々|[四廿]日)市市|西八代郡市川三郷町|",
        "神崎郡市川町|高市郡(高取町|明日香村)|(吉野郡)?下市町|(杵島郡)?大町町)(.+)"
    )).unwrap();
    let re2 = Regex::new("^(.+[市区町村])(.+)").unwrap();

    match re1.captures(address) {
        Some(m) => {
            match re2.captures(&m[12]) {
                Some(m2) => (format!("{}{}",(&m[1]),(&m2[1])), (&m2[2]).to_string()),
                None => ((&m[1]).to_string(), (&m[12]).to_string())
            }
        },
        None => {
            match re2.captures(address) {
                Some(m2) => ((&m2[1]).to_string(), (&m2[2]).to_string()),
                None => ("".to_string(), address.to_string())
            }
        }
    }
}



fn main() {
    let (prefecture, tmp1) = get_prefecture("大阪府大阪市北区ほげほげ9丁目99-909");
    let (city, tmp2) = get_city(&tmp1);

    println!("Prefecture: {:?}", prefecture);
    println!("City: {:?}", city);
    println!("...: {:?}", tmp2);
}

みんなのM5Stack入門

以前から気になっていた M5Stack を入門書&タイアップのスターターキットが発売されたのが良い機会かなと思い、スイッチサイエンスで注文。 とりあえず商品が届くまでの間、その入門書である「みんなのM5Stack入門」(下島健彦・リックテレコム)を買って読んでみた。

内容はハードの紹介から始まって、単体で動作するプログラムで画面やボタン、内臓の9軸センサの制御の仕方を学んで、その後、定番のLチカなど 各種センサやデバイスを繋いでのデジタル・アナログの入出力ライブラリの解説、最後に内蔵のWIFIBluetoothを利用した通信の解説とM5Stackでできることを一通り網羅している。 入門書としては一般的な手堅い内容。電子工作の基礎的な話は控えめでプログラム主体で進んでいくためプログラマとしては馴染みやすいのが個人的には気に入ったところ。サンプルの 電子工作も非接触の温度センサーとサーボモーターを利用して簡易なサーモグラフィを作成するなど興味深い題材を扱ってる。

ブツが届く前に読む本としては期待度がMAXにまで高まる良い本だった。

Amazon : みんなのM5Stack入門

iPhone11 Pro に機種変更

先日の連休、近所のソフトバンクで端末を iPhone X から iPhone11 Pro に機種変更した。
2年ぶりの機種変更だが、契約の説明が店員の口頭から動画の視聴になってたり、旧端末の店頭での回収を受け付けてくれなくなったりといろいろ進化?していて戸惑うが、iPadでの契約のサインが未だに Apple Pencil ではなくゴム頭のスタイラスでさせたりするのがソフトバンクの駄目なとこだろう。

二、三日使ってみたけど、カメラが良くなった(超広角とナイトモードは良い)以外は体感的に大きく変わるものはなく感動はまあそれなりといった感じ。iPhone7、iPhone X と2回連続でスクリーンにヒビを入れてしまったので、今回は嫌々ながらケースとガラスフィルムを付けたのが一番の感覚的な違いだろうか。