昆布大好き!

主にプログラミングの技メモ

エクスプローラからコマンドプロンプトを開く

エクスプローラからターミナルを開くとPowerShellが起動するようになっています。 f:id:liincarnate:20181204135759p:plain

PowerShellよりもコマンドプロンプトを使いたい場合もあるかと思います。 そんな時はcmdのコマンドを実行します。見た目はPowerShellのままっぽいですがコマンドプロンプトが起動されます。

ついでに、PowerShellコマンドプロンプトから下のコマンドを実行するとカレントディレクトリでエクスプローラの新しいウインドウが開きます。

>explorer .

Linux上のイージーなテキストテンプレート

やりたいこと

<!-- list.txt -->
あああ いいい ううう
かかか ききき くくく
さささ ししし すすす

みたいなリストと、

<!-- template.m4 -->
<ul>
  <li>m4_arg1</li>
  <li>m4_arg2</li>
  <li>m4_arg3</li>
</ul>

みたいなテンプレートから、

<ul>
  <li>あああ</li>
  <li>いいい</li>
  <li>ううう</li>
</ul>
<ul>
  <li>かかか</li>
  <li>ききき</li>
  <li>くくく</li>
</ul>
<ul>
  <li>さささ</li>
  <li>ししし</li>
  <li>すすす</li>
</ul>

みたいなテキスト置き換えをしたい。

【良かった方法】シェルスクリプト & sed

sedって最高だな!

#a.sh
$ sed -e s/m4_arg1/$1/ -e s/m4_arg2/$2/ -e s/m4_arg3/$3/ template.m4
cat a.list | xargs -n 3 ./a.sh

【あまり良くなかった方法】awk & m4 & シェルスクリプト

めんどかったやり方。

# a.awk
{ printf("-Dm4_arg1=%s -Dm4_arg2=%s -Dm4_arg3=%s\n", $1, $3, $2) }
$ awk -f a.awk list.txt | xargs -i echo m4 {} template.txt > a.sh
$ source a.sh

a.shの中身はこんな感じ

m4 -Dm4_arg2=あああ いいい ううう -Dm4_arg2= -Dm4_arg3= template.txt
m4 -Dm4_arg2=かかか ききき くくく -Dm4_arg2= -Dm4_arg3= template.txt
m4 -Dm4_arg2=さささ ししし すすす -Dm4_arg2= -Dm4_arg3= template.txt

字面ではこんなでもうまくいきそうだけど、 引数が思ったように処理されない。

awk -f d.awk a.list | xargs -i m4 {} template.txt
<ul>
  <li>m4_arg1</li>
  <li>あああ いいい ううう -Dm4_arg2= -Dm4_arg3=</li>
  <li>m4_arg3</li>
</ul>

<ul>
  <li>m4_arg1</li>
  <li>かかか ききき くくく -Dm4_arg2= -Dm4_arg3=</li>
  <li>m4_arg3</li>
</ul>

<ul>
  <li>m4_arg1</li>
  <li>さささ ししし すすす -Dm4_arg2= -Dm4_arg3=</li>
  <li>m4_arg3</li>
</ul>

【良くなかった方法】awk

awkのコードにテンプレートを書く。 すごくめんどい

{ printf(" \t<ul>\n\t\t<li>%s</li>\n \t\t<li>%s</li>\n\t\t<li>%s</li>\n\t</ul>\n", $1, $2, $3) }

【ダメだった方法】シェルスクリプト & tr

trはsedの代わりはできない。マルチバイトお断り。

#b.sh
cat template.txt | tr m4_arg1 $1 | tr m4_arg2 $2 | tr m4_arg3 $3
cat a.list | xargs -n 3 ./b.sh

二十四節季(明治28年)

どういう訳なのか100年以上前の節季を調べました。

小寒 1895-1-5 22:07

大寒 1895-1-20 15:37

立春 1895-2-4 9:57

雨水 1895-2-19 6:9

啓蟄 1895-3-6 4:31

春分 1895-3-21 5:49

生命 1895-4-5 10:4

穀雨 1895-4-20 17:38

立夏 1895-5-6 4:7

小満 1895-5-21 17:26

芒種 1895-6-6 8:49

夏至 1895-6-22 1:44

小暑 1895-7-7 19:15

大暑 1895-7-23 12:33

立秋 1895-8-8 4:50

処暑 1895-8-23 19:12

白露 1895-9-8 7:12

秋分 1895-9-23 16:10

寒露 1895-10-8 22:8

霜降 1895-10-24 0:46

立冬 1895-11-8 0:36

小雪 1895-11-22 21:41

大雪 1895-12-7 16:55

冬至 1895-12-22 10:38

PHPの範囲チェック

<?php
$n = 19;
$ok = true;
$ok = $ok and is_numeric('a');
$ok = $ok and ($n < 1);
$ok = $ok and isset($no_var);
print(var_dump($ok));
?>

bool(true)

になる。

<?php
$n = 19;
$ok = true;
$ok = $ok && is_numeric('a');
$ok = $ok && ($n < 1);
$ok = $ok && isset($no_var);
print(var_dump($ok));
?>

bool(false)

と意図したとおりの判定になる。

論理演算子(and)よりも代入演算子(=)の方が優先順が上であるためこうなるのだが、 PHPプログラマはこの結果に納得できているのかしら。

CとPythonを合わせて使う(その1)

目的

パラメータ設定ファイルをPythonスクリプトで書きたくなったのでやってみま した。

出来るようになること

次のように、数式でパラメータを指定したり、タプル型をパラメータにすることが出来るようになります。

x = 1
tpl1 = (x, 20*x+5, 300*x)
tpl2 = (x+2, 30*x+1, 400*x)

方法

Cコードです。

#include    <iostream>
#include    <Python.h>

void main(int argc, char *argv[])
{
    // Pythonランタイムの初期化
    Py_Initialize();
    // mainモジュールを取得
    PyObject *module = PyImport_AddModule("__main__");
    // スクリプトを実行
    MyPyRunFile("setting.py");

    // Pythonランタイム中の"tpl1"変数を参照
    PyObject *tmp = PyObject_GetAttrString(module, "tpl1");
    int n1, n2, n3;
    // 書式を指定して変数の値を取り出す
    PyArg_Parse(tmp, "(iii)", &n1, &n2, &n3);
    printf("tpl1 = (%d, %d, %d)\n", n1, n2, n3);

    // Pythonランタイムの始末
    Py_Finalize();
}

実行結果

tpl1 = (1, 25, 300)

Cのコードの中でPythonランタイムを起動、 任意のタイミングでスクリプトを実行してパラメータをランタイムに読み込ませます。 読み込ませた値をCコード側から読み取ります。

スクリプトで設定した値は、mainモジュールへの変数に設定されています。 Cコードから参照するには書式指定文字列で型を指定して変数を参照します。

ビルドの際には、インストールしたPythonに合わせてx86かx64かを合わせる必要があります。

少し楽をする

書式指定を省略して楽ができるようにGetTupleクラスを作ります。

#include    <iostream>
#include    <Python.h>

// Pythonタプル型読み取り
class GetTuple {
public :
    static void Initialize();

public :
    // 読み取り関数
    template <class ... Types>
    static void Get(const char *var, Types ... args)
    {
        char fmt[128];
        fmt[0] = '(';
        getPyParseFormat(fmt+1, args ...);
        PyObject *tmp = PyObject_GetAttrString(_mainModule, var);
        PyArg_Parse(tmp, fmt, args ...);
    }

private :
    // Pythonモジュールハンドラ
    static PyObject *_mainModule;

    // パース指定書式を型判定とオーバーロードとテンプレートを駆使して作成
    static void getPyParseFormat(char *sz) {
        *sz = ')';
        *(sz+1) = '\0';
    }

    // 同上
    template <typename T, class ... Types>
    static void getPyParseFormat(char *sz, T type, Types ... args) {
        if ( typeid(*type) == typeid(int) ) {
            *sz = 'i';
        } else if ( typeid(*type) == typeid(float) ){
            *sz = 'f';
        } else if ( typeid(*type) == typeid(wchar_t) ){
            *sz = 'u';
        } else {
            *sz = 's';
        }

        getPyParseFormat(sz+1, args ...);
    }

};

PyObject *GetTuple::_mainModule;

void GetTuple::Initialize()
{
    _mainModule = PyImport_AddModule("__main__");
}

// Pythonスクリプト実行
bool MyPyRunFile(const char *filename)
{
    PyObject *obj = Py_BuildValue("s", filename);
    FILE *file = _Py_fopen_obj(obj, "r+");
    if (file != nullptr) {
        PyRun_SimpleFileEx(file, filename, 1);
        return true;
    }
    return false;
}

void main(int argc, char *argv[])
{
    // Pythonランタイムの初期化
    Py_Initialize();
    // mainモジュールを取得
    PyObject *module = PyImport_AddModule("__main__");
    // スクリプトを実行
    MyPyRunFile("setting.py");

    GetTuple::Initialize();
    // 細工を使って"tpl2"変数の値を取り出す
    GetTuple::Get("tpl2", &n1, &n2, &n3);
    printf("tpl2 = (%d, %d, %d)\n", n1, n2, n3);
    // Pythonランタイムの始末
    Py_Finalize();
}

実行結果

tpl2 = (3, 31, 400)

C++の拡張されたテンプレート機能やオーバーロードなどを多用しています。 args …の部分は、引数で渡ってきた変数がごそっと入ってくる、と思って下さい。

HTTPConnectionを使ってGETリクエスト

Pythonには豊富な標準ライブラリが付属しています。 今回はHTTPConnection (HTTPSConnection)を使ってhttp(https)サーバからレスポンスを取得 してみます。

httpでは主にPOSTコマンドとGETコマンドが使われますが、ここではGETコマンドでリク エストします。 GETコマンドではURLの後ろにパラメータ引数を追加して一緒にサーバへ渡します。

出来ること

  • HTML(ソース)のリクエス
  • パラメータを指定したリクエス
  • REST APIの使用

httpsプロトコルで接続する場合は、HTTPSconnectionを使います。 オブジェクトの生成の時に使い分けるだけでよいです。

# conn =  HTTPConnection('www.google.co.jp')
conn =  HTTPSConnection('www.google.co.jp')

それでは、ソースコードを見ていきます。

from http.client import HTTPSConnection, HTTPConnection
from urllib.parse import urlencode
# オブジェクトを生成します。サーバのホスト名を指定します
conn =  HTTPSConnection('www.google.co.jp')
# GETリクエストと一緒指定するヘッダです
getHeader = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.90 Safari/537.36 Vivaldi/1.91.867.38',
    }
# コマンド、パス、ヘッダを指定してサーバへリクエストを送信します
# 検索ワードにオオサンショウウオを指定しています
conn.request('GET', '/search?' + urlencode({'q':'オオサンショウウオ'}), headers=getHeader)
# レスポンスを取得します。バイナリデータです。
res = conn.getresponse()
bs = res.read()
res = bs
# バイナリデータをエンコードしてテキストを取得します
print('response:', res.decode('utf-8'))
conn.close()

conn.requestのheadersに指定しているヘッダ情報は指定していなくても相手のサーバ によっては問題なくレスポンスが取得できます。 上記の値(‘Mozilla/5.0…’)は手元のブラウザのGETリクエストで指定されていた値を ものですので常にこれで正しいという値ではないかもしれません。

urlencodeでパラメータをURLエンコードしています。

>>> print(urlencode({'q':'オオサンショウウオ'}))
>>> q=%E3%83%A9%E3%82%A4%E3%83%B3%E3%83%90%E3%83%AC%E3%83%AB

パスの後の'?‘にこれを繋いでリクエストを生成します。

付録

ヘッダにAccept-Encodingを指定するとサーバは圧縮エンコードされたデータを返す場合があります。 この場合gzipライブラリでデコードしてからテキストにします。

getHeader = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.90 Safari/537.36 Vivaldi/1.91.867.38',
    'Accept-Encoding': 'gzip, deflate',
    }
# ....
res = conn.getresponse()
bs = res.read()
# バイナリデータを展開します
res = gzip.decompress(bs)
# バイナリデータをエンコードしてテキストを取得します
print('response:', res.decode('utf-8'))

会話にて

揚げ足取りです。 プログラマ同士で会話していると、言葉遣いが気になることがありまして。

  • デファイン定義

C/C++プリプロセッサのマクロ定義のことを指しています。意味かぶってる…

言ってることはわかる。わかるけど.NETでと言ってほしかった。