読者です 読者をやめる 読者になる 読者になる

なにも わからぬ

パソコンとプログラミング関係をメモっていきたい

Hello, Kotlin

Kotlin

Javaも書けないのにbetter Javaとして評判のKotlinに手を出してみた。とりあえず定番っぽい以下の本を買う。

もちろんJava経験者がターゲットなので、「第3章:ガイドツアー」からなかなか厳しい。けど「第4章:基本的な文法」からはよくある言語仕様の紹介になり、ずぶの素人でもついていけそうな感じになっている。

最終的にはAndroidアプリを作るのが目標だけど、とりあえずはIntelliJ IDEAで純粋にKotlinをいじってみよう。Hello worldを言わせるだけじゃ面白くないので、昔やったことのある穴掘り法による迷路作成を適当に実装してみた。

import java.util.*

fun createMap(xLength: Int, yLength: Int): Array<Array<Int>> {
    var map = Array(yLength, {Array(xLength, {0})})

    fun buildRoad(posX: Int, posY: Int) {
        val directions: List<Int> = mutableListOf(0,1,2,3)
        Collections.shuffle(directions)
        for (i in directions) {
            val distance:Array<Int> = when(i) {
                0 -> arrayOf(0, -1)
                1 -> arrayOf(1, 0)
                2 -> arrayOf(0, 1)
                3 -> arrayOf(-1, 0)
                else -> arrayOf(0, 0)
            }
            val dest:Array<Int> = arrayOf(posX+distance[0]*2, posY+distance[1]*2)
            if (
                dest[0] in 0..xLength-1
                && dest[1] in 0..yLength-1
                && map[dest[1]][dest[0]] == 0
            ) {
                map[posY+distance[1]][posX+distance[0]] = 1
                map[dest[1]][dest[0]] = 1
                buildRoad(dest[0], dest[1])
                break
            }
        }
    }

    map[1][1] = 1
    buildRoad(1, 1)
    for (i in 0..100) {
        val r = Random()
        while(true) {
            val x = r.nextInt(xLength)
            val y = r.nextInt(yLength)
            if (x%2 == 1 && y%2 == 1 && map[y][x] == 1) {
                buildRoad(x, y)
                break
            }
        }
    }
    return map
}

fun main(args: Array<String>) {
    val scanner = Scanner(System.`in`)
    var input: String
    var length: Int
    while (true) {
        println("迷路の1辺のマス数を10以上で入力(偶数は奇数に繰り上げ)")
        input = scanner.nextLine()
        if (Regex("""\d{2}""").matches(input)) {
            length = if(input.toInt()%2 == 1) input.toInt() else input.toInt()+1
            break
        }
    }
    var map: Array<Array<Int>> = createMap(length, length)

    for (y: Int in map.indices) {
        var line:String = ""
        for (x: Int in map[y].indices)
            line += if (map[y][x] == 0) "#" else "."
        println(line)
    }
}

実行するとこんな感じに f:id:htkb:20161101235416j:plain

難しいけど少しずつやっていこう。

複数回献血クラブにログインしデータを取得するスクリプト

Python3

日本赤十字社の複数回献血クラブに登録すると、ネット上でこれまでの献血時のデータを閲覧できたり、
f:id:htkb:20161027001127j:plain
こんな風にグラフにして見せてくれたりするため、ちょくちょく献血している人には便利。しかし献血後にデータ反映まで数日のラグがあったり、データ閲覧のページにたどり着くまで2回ほどログイン作業が必要だったりとチェックが面倒だったりする。そこで、python+requestsでログインを試みてみる。

firefoxで複数回献血クラブにログインしつつLive HTTP headersを覗きながら試してみると、

  1. 会員ログインページ(https://www.kenketsu.jp/nskc/user/login.asp)に {"mode":"login", "user_id":数字10桁の会員ID, "password":パスワード}をPOSTしクッキーを得る
  2. 会員メニュー内の献血記録のパス入力ページ(https://www.kenketsu.jp/nskc/user/done/passwdexe.asp)に 1. で得たクッキーと {"mode":"login", "passwd":4桁のパスワード, "dummy":""}をPOSTする

のみで良いことがわかった。以下はとりあえず最終の記録の日時を得るだけのスクリプト

import requests
import re

def get_latest_date():
    # 以下3つを自分の情報に変更する
    user_id = "0000000000"
    login_password = "password"
    record_password = "0000"

    login_url = "https://www.kenketsu.jp/nskc/user/login.asp"
    login_data = {"mode": "login", "user_id": user_id, "password": login_password}
    record_url = "https://www.kenketsu.jp/nskc/user/done/passwdexe.asp"
    record_data = {"mode": "login", "passwd": record_password, "dummy": ""}

    # まずは会員ログインしてログイン状態のクッキーをもらう
    resp = requests.post(url=login_url, data=login_data)

    # もらったクッキーを使って献血記録にアクセス
    resp2 = requests.post(url=record_url, data=record_data, cookies=resp.cookies)

    # あとはresp2.textを煮るなり焼くなり
    html = resp2.text
    latest_date = re.search(r"H\d+\.\d+\.\d+", html)
    if latest_date is not None:
        return latest_date.group()
    else:
        return None

Xperia XA Ultraの気になったところ・イマイチなところ

Xperia XA Ultra スマートフォン

ファーストインプレッション からネガティブな感想を並べてしまったが、総合的に満足とはいえミドルロー程度の性能なので割り切る必要はいろいろと出てくる。使っていて気づいた点を。

続きを読む

Xperia XA Ultraでデレステ

スマートフォン Xperia XA Ultra


音楽が著作権違反と言われ即消されてたので音消した。音ゲーなのに。

SoCの性能良ければ快適ってわけじゃないデレステXperia XA Ultraの100万倍くらいのGPU性能を誇るShield Tabletでは2D軽量でカクついたり指が画面に3本以上触れるとロングノーツが即座に切れるなどの怪現象に見舞われて忍耐力が養われたが、XA Ultraは2D軽量ならスムーズに動き発熱もあまりなく快適そのもの。

ただ設定→音と通知→オーディオ設定→ClearAudio+にチェックが入ってると音ズレがえらいことになるので必ずオフ。
f:id:htkb:20161019213324j:plain

また、イヤホンの有無でタイミング調節が異なったり微妙な癖はあるようだ。今のところタイミング調節はイヤホンありで27前後、スピーカーで29~30のよう。タップ音も付けるとまた違ってきて、最適値を見つけるのはやや骨が折れそう。

f:id:htkb:20161019220935j:plain もちろん3Dはダメダメです。

追記:タップ音ありにすると音楽に対して譜面と判定がどんどん後ろにずれていって音ゲーにならない。多分性能の問題なのでタップ音ありでやりたい人にはダメそう。

こんにちは Xperia XA Ultra

スマートフォン Xperia XA Ultra

f:id:htkb:20161018210200j:plain

続きを読む

HTTPライブラリで得たhtml文字列をブラウザで表示する

Python3

requestsなどのHTTPライブラリで取得したHTMLの内容を確認するのに、いちいち文字コードを変換したりタグを消したりしてコンソール上でチェックするのはめんどくさい。その都度いちいちファイルに保存してそれをブラウザに持ってくのもやっぱめんどくさい。ということでtempfileでhtmlファイルを作り、そのパスをブラウザで開かせるまでを関数化してみた。

import tempfile
import webbrowser

def view_in_browser(content):
    ''' bytes型をtemfileに書き込んでそのパスをブラウザに送る '''

    with tempfile.NamedTemporaryFile(suffix=".html", delete=False) as tf:
        tf.write(content)
        webbrowser.open(tf.name)

tempfile.NamedTemporaryFileはデフォルトでmode="w+b"なので文字列じゃなくてバイト列を渡さなければならない。もちろんmode="w"にすれば文字列を受け付けるけど、そうすると結局文字コード指定で一手間かかるだけだしrequestsのレスポンスのcontentプロパティにはバイト列が入ってるからデフォルトのままでいいと思う。

delete=True(デフォルト)だと上記のコードではwithブロックを出た時点でファイルが削除されるので、ブラウザが読み込もうとした時には既にファイルが無いということになる。withブロック内で処理を止めるならdelete=Trueでもいいけど。


requestsはHTTPヘッダのContent-Typecharset=hogehogeが入ってないと、HTMLのmetaに何が書いてあっても読んでくれない(HTMLパーサじゃないから当たり前)ので日本語文書は高確率で文字化けする。でも大抵r.apparent_encodingに正しい文字コードが入ってるから

r.encoding = r.apparent_encoding

文字コードの不一致は大体解消する模様。参考:https://blog.aoshiman.org/entry/118/

なお、r.textの中身は文字列なので操作するときに文字コードがおかしいと怒られるが、上記の通りr.contentバイト列なのでファイルに書き出すならこっち使った方が楽。ブラウザが表示するときはもちろんmeta要素見るわけだし。


関係ないけど、ブラウザの環境変数だけ見れば、requestsに以下のヘッダ付けて最新のWin10 x64 Edgeと同等に見えるかな?

headers = {
        "Accept": "text/html, application/xhtml+xml, image/jxr, */*",
        "Accept-Language": "ja",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393"
}

LANG=C環境下のPython3でUnicodeEncodeError

Python3

非Xのコンソールで日本語メッセージが文字化けするのでサーバのlinuxLANG=Cにしていたが、pythonUTF-8のファイルを読もうとすると

UnicodeEncodeError: 'ascii' codec can't encode characters in position 45-49: ordinal not in range(128)

のようなエラーが出て困っていた。print()などでUTF-8文字列を出力しなくても

with open(filepath, encoding="utf-8") as fp:

の行でエラーが出てる。でググったらPythonでLANG=Cのときのエンコーディングの注意ということのよう。LANG=Cのまま解決するにはリンク先の通りだが、自分の場合はそもそもLANG=en_US.UTF-8で済む話であった。