Kuzunoha-NEのブログ

プログラミングなどの勉強をしてます

【雑記】不定期更新に変更します。

こんばんは、葛の葉です。

さて、5/31をもって職業プログラマーとして満二年をとげ、6月からプログラマー三年生になりました。当時、駆け出しプログラマーだった私も、少しはプロっぽくなったのかなぁと思います。プログラマーという夢をかなえることができてとても良かった。

前回にもちょっと書いたのですが、このブログの更新を不定期にしようと思います。

多分、多くの人は知らないと思うのですが、私はこのブログを週1で書いてて、それを2年間続けていました。ちょうど2年前の6月の最初の週から定期的に更新しています。

当時、樺沢紫苑さんのアウトプット大全という本がベストセラーになると、右に左にアウトプットという言葉が流行り、このブログもその位置付けで始めることになりました。

ブログを書くこと自体は結構楽しくて1年くらいは書いてて楽しかったです。ただ、途中からマンネリとなりました。

プログラマーのアウトプットはブログに書くこと以外にもある気がします。実際にアプリケーションを作るのもアウトプットです。作りきるということができれば、それは大きなアウトプットになると思います。

なので、今後は自分の作ってみたいものを作りつつ、それができたらアーキテクチャの話なども含めてブログに書こうかなぁ思います。

【Typescript】ネストなObjectが持つ文字列の全ての長さを整える

こんばんは葛の葉です。

ネストになっているオブジェクトを処理しようとすることが多くて、そのネストの深さがものによってまちまちな場合の処理書くの辛いなぁっている昨今なんですよ。色々と考えたら、これは再起処理でコードを書くのがいいんじゃないかなぁと思って今回書いてみました。

再起処理でobjectかそうでないかを判断する。

reflexiveFuncToObjectという関数を作成しました。これは第一引数に対象となるオブジェクトを入れ、第二引数にそのオブジェクトに実行させたい関数を入れます。第三引数以降はその関数に与える引数になります。この関数を実行するとオブジェクトのそれぞれのプロパティのデータ型がObjectかそうでないかを判定し、Objectの場合は再びreflexiveFuncToObject関数を実行し、そうでない場合は第二引数の関数を実行します。

interface anyObj {
  [key: string]: any;
}

const reflexiveFuncToObject = (obj: anyObj, func: Function, ...args: any) => {
  const copy:anyObj = {...{}, ...obj};
  Object.keys(copy).forEach((key: string) => {
    if (typeof copy[key] === "object") {
      reflexiveFuncToObject(copy[key], func, ...args);
    } else {
      copy[key] = func(copy[key], ...args);
    }
  });
  return copy;
};

以下のような値を変更するような関数を作ります。reflexiveFuncToObject関数の第一引数に入れてあげるようにします。

const truncate = (prop:any, l: number) => {
  if (typeof prop !== "string")  return prop;
  return l >= prop.length ? prop : (prop.substr(0, l) + "...");
};

const add = (prop: any, num: number) => {
  if (typeof prop !== "number") return prop;
  return prop + num;
};

以下の状況においてはこのようになります。

const object1 = {
  a: "aaaaa",
  b: "bbbbb",
  c: 1,
};
console.log(reflexiveFuncToObject(object1, truncate, 1)); // { a: 'a...', b: 'b...', c: 1 }
console.log(reflexiveFuncToObject(object1, add, 1)); // { a: 'aaaaa', b: 'bbbbb', c: 2 }

再起処理って初めて書いたかも

2年この仕事してるんだけど再起処理は初めて書いたかもしれない。今回再起処理を書いてみようと思ったのはチャレンジ心だけなんだ。もっといい処理の仕方は絶対あると思うけど、ネストなオブジェクトに対して再起処理はいいアプローチだと思っている。今後もチャレンジしてみたい。

最初はしょぼくたっていいんだ。後からかっこよくすりゃいいんだ。

追伸

次回以降は不定期に気まぐれに更新します。

【TypeScript】Objectのディープコピー

こんばんは葛の葉です。

Javascriptのディープコピーをちょっと書きます。Javascriptではconst copyedObj = JSON.parse(JSON.stringify(obj));を使うと思います。

const obj1 = {
  hoge: 1,
  piyo: "hiyoko",
  fuga: true
};

const copyedObj1 = JSON.parse(JSON.stringify(obj1));
obj1.hoge = 2;
console.log(copyedObj1.hoge === 1); // true
console.log(copyedObj1); // { hoge: 1, piyo: 'hiyoko', fuga: true }

しかし、以下のStackOverflowには

Fast cloning with data loss - JSON.parse/stringify

If you do not use Dates, functions, undefined, Infinity, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays or other complex types within your object, a very simple one liner to deep clone an object is:

 JSON.parse(JSON.stringify(object))

stackoverflow.com

Date型や関数, undefined, Infinityや正規表現、その他もろもろのものについてはコピーできないということです。

const obj2 = {
  moge: undefined,
  date: new Date("2020/01/01Z"),
  func: function () {
    return 'hogehoge';
  },
  reg: /^https/g
};

const copyedObj2 = JSON.parse(JSON.stringify(obj2));
console.log(copyedObj2); // { date: '2020-01-01T00:00:00.000Z', reg: {} };

Date型はJSONになるタイミングでISO 8601形式のstring型になります。正規表現オブジェクトについては、空のオブジェクトに変更されます。こういった一部の型についてはコピーすることが出来ないようです。おそらくJsonが文字列しかないからなのかなぁって思います。

じゃあどうやってディープコピーするの?

先のStackOverflowにも書いてあったんですけど、頑張ってコード書いてもいいけど基本的にライブラリやフレームワークのメソッドを使おうってことみたいです。私が使ったのはこちらのライブラリ。

www.npmjs.com

Typescriptの型はこちら

www.npmjs.com

import clone from "clone";

const obj2 = {
  moge: undefined,
  date: new Date("2020/01/01Z"),
  func: function () {
    return 'hogehoge';
  },
  reg: /^https/g
};

const copyedObj2 = clone(obj2);
console.log(copyedObj2);
/*
{
  moge: undefined,
  date: 2020-01-01T00:00:00.000Z,
  func: [Function: func],
  reg: /^https/g
}
*/ 
console.log(copyedObj2.func()); // hogehoge

【Python】janomeで形態素解析をしてもらう

こんばんは葛の葉です。

Pythonにはjanomeという形態素解析が出来るモジュールがあるみたいです。

mocobeta.github.io

形態素解析wikipediaを参照してください。

ja.wikipedia.org

青空文庫にある「坊っちゃん」の一文を形態素分析してみます。

www.aozora.gr.jp

親譲《おやゆず》りの無鉄砲《むてっぽう》で小供の時から損ばかりしている。小学校に居る時分学校の二階から飛び降りて一週間ほど腰《こし》を抜《ぬ》かした事がある。なぜそんな無闇《むやみ》をしたと聞く人があるかも知れぬ。別段深い理由でもない。新築の二階から首を出していたら、同級生の一人が冗談《じょうだん》に、いくら威張《いば》っても、そこから飛び降りる事は出来まい。弱虫やーい。と囃《はや》したからである。小使《こづかい》に負ぶさって帰って来た時、おやじが大きな眼《め》をして二階ぐらいから飛び降りて腰を抜かす奴《やつ》があるかと云《い》ったから、この次は抜かさずに飛んで見せますと答えた。

これをboc.txtとして保存し、pythonではこれをロードして使ってみます。

from janome.tokenizer import Tokenizer

import re

t = Tokenizer()

moji = ""

with open("./boc.txt", mode="r", encoding="utf-8") as text:
  moji = text.read()

moji = re.sub("《[^》]+》", "", moji)
moji_list = moji.split("。")
moji_list.pop()

s = [t.tokenize(sentence) for sentence in moji_list]

# 全文の形態素解析の表示は辛いので一文だけという意味で[0]
for i in s[0]:
  print(i)

"""
親譲り  名詞,一般,*,*,*,*,親譲り,オヤユズリ,オヤユズリ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
無鉄砲  名詞,一般,*,*,*,*,無鉄砲,ムテッポウ,ムテッポー
で      助詞,格助詞,一般,*,*,*,で,デ,デ
小      接頭詞,名詞接続,*,*,*,*,小,ショウ,ショー
供      名詞,サ変接続,*,*,*,*,供,キョウ,キョー
の      助詞,連体化,*,*,*,*,の,ノ,ノ
時      名詞,非自立,副詞可能,*,*,*,時,トキ,トキ
から    助詞,格助詞,一般,*,*,*,から,カラ,カラ
損      名詞,一般,*,*,*,*,損,ソン,ソン
ばかり  助詞,副助詞,*,*,*,*,ばかり,バカリ,バカリ
し      動詞,自立,*,*,サ変・スル,連用形,する,シ,シ
て      助詞,接続助詞,*,*,*,*,て,テ,テ
いる    動詞,非自立,*,*,一段,基本形,いる,イル,イル
"""

まず、ルビが不要なので正規表現で削除します。また、一文ずつのほうが解析として見やすいので一文にします。

tokenizeメソッドを使うことで文字列を形態素解析し、形態素を要素としてリストとして出力します。本当にこれ無料で使っていいのか?って思う。

わかち書きもしてもらう

janomeにはわかち書きにしてくれるモードもついているので、それも使ってみます。

ja.wikipedia.org

from janome.tokenizer import Tokenizer

import re

t = Tokenizer()

moji = ""

with open("./boc.txt", mode="r", encoding="utf-8") as text:
  moji = text.read()

moji = re.sub("《[^》]+》", "", moji)
moji_list = moji.split("。")
moji_list.pop()

s = [t.tokenize(sentence, wakati=True) for sentence in moji_list]

# 全文の形態素解析の表示は辛いので一文だけという意味で[0]
print(s[0])
"""
['親譲り', 'の', '無鉄砲', 'で', '小', '供', 'の', '時', 'から', '損', 'ばかり', 'し', 'て', 'いる']
"""

【python】collections.Counterオブジェクトで文字数を保持する

こんばんは葛の葉です。

個人的な話ですが、Pythonを久しぶりに使うことになりそうなので勉強中です。

久しぶりに触ったらcollections.Counterオブジェクトというものが出てきたので触ってみることにしました。

collections.Counter

collections.Counterは辞書型のサブクラスで、Keyに要素を入れ、valueがそのカウントを保存して使うものらしいです。

公式ドキュメントはこちら↓。

docs.python.org

かの有名な復活の呪文の数をCounterオブジェクトへ

ドラクエ2に出てくる「もょもと」の復活の呪文に出現する「ぺ」の数をカウントして保存してみます。

ゆうていみやおうきむこうほりいゆうじとりやまあきらぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺ
import collections

password = "ゆうていみやおうきむこうほりいゆうじとりやまあきらぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺ"
counter = collections.Counter()
parsed_password = list(password)

for i in parsed_password:
  counter[i] += 1

print(counter)
# Counter({'ぺ': 27, 'う': 4, 'ゆ': 2, 'い': 2, 'や': 2, 'き': 2, 'り': 2, 'て': 1, 'み': 1, 'お': 1, 'む': 1, 'こ': 1, 'ほ': 1, 'じ': 1, 'と': 1, 'ま': 1, 'あ': 1, 'ら': 1})

ぺの数は27個らしい!

ついでにピクル化もしてみよう

Pythonではpickleモジュールを使ったシリアライズとデシリアライズもよくやってるようですのでこちらも使ってみます。

pickleの公式ドキュメントはこちら

docs.python.org

import collections
import pickle

password = "ゆうていみやおうきむこうほりいゆうじとりやまあきらぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺぺ"
counter = collections.Counter()
parsed_password = list(password)

for i in parsed_password:
  counter[i] += 1

print(counter)# Counter({'ぺ': 27, 'う': 4, 'ゆ': 2, 'い': 2, 'や': 2, 'き': 2, 'り': 2, 'て': 1, 'み': 1, 'お': 1, 'む': 1, 'こ': 1, 'ほ': 1, 'じ': 1, 'と': 1, 'ま': 1, 'あ': 1, 'ら': 1})

with open("count_password.pkl", "wb") as f:
  pickle.dump(counter, f)

こうすることでカレントディレクトリにcount_password.pklというバイナリファイルが作成されます。このバイナリファイルはpythonでロードすることが出来ます。公式ドキュメントにも記載はありましたが、セキュアには出来ないから安全と確信できないピクルは使わないようにとのこと。

import pickle

with open("count_password.pkl", "rb") as f:
  counter = pickle.load(f)

print(counter)
# Counter({'ぺ': 27, 'う': 4, 'ゆ': 2, 'い': 2, 'や': 2, 'き': 2, 'り': 2, 'て': 1, 'み': 1, 'お': 1, 'む': 1, 'こ': 1, 'ほ': 1, 'じ': 1, 'と': 1, 'ま': 1, 'あ': 1, 'ら': 1})

先と同じものが標準出力に表示されました。

【curl】「unable to get local issuer certificate」って出た

こんばんは葛の葉です。

いつものアホ面でcurlを叩いたら見慣れないErrorが出てきました。

$ curl -vI https://***********.htm
*   Trying ***.***.***.***...
* TCP_NODELAY set
* Connected to ********** (***.***.***.***) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS alert, Server hello (2):
* SSL certificate problem: unable to get local issuer certificate
* stopped the pause stream!
* Closing connection 0

curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

unable to get local issuer certificateとはローカル発行者証明書を取得できませんと書かれているみたいです。すなわち、httpsの証明書の証明するルート証明書が取得できないみたいです。

そもそも、https通信における安全性の担保は暗号化通信とサーバーが安全であることを証明するSSLサーバー証明書が必要です。そのSSLサーバー証明書が安全かどうかを証明する認証局があります。その認証局をリスト化したルート証明書があるのですが、ブラウザやソフトウェアにはデフォルトでいくつかの認証局が記載されてはいるものの、全部の認証局を網羅しているわけではないみたいです。

今回はそのデフォルトのルート証明書内にそのurlの認証局が見当たらない?ようで、curlは通信を拒否したみたいです。

証明書を気にせず通信するという方法もあり、curl -k (該当url)とするみたいです。

ちょっと気になったのは今回のその認証局そのものが本当に信用できるのかというところで、私にはなんとも判断できませんでした。某有名なレンタルサーバー屋さんにも使われているみたいですが、それが必ずしも信用に値するとは限らないですし。

証明書の追加方法は以下のURLを見てみてください。

curl.haxx.se

【JavaScript】toISOString()でISO規格な時間記述を得る

こんばんは葛の葉です。

さて、JavaScriptのDateオブジェクトにはtoISOString()というメソッドが存在します。このメソッドは、ISO 8601に定められる国際規格で記述された日時の表記を出力できるものとなっています。返却値の型はstringになります。

developer.mozilla.org

const date = new Date("2020/04/01");
console.log(date.toISOString()); // '2020-03-31T15:00:00.000Z'

'2020-03-31T15:00:00.000Z'これがISO 8601規格に則った日時の表記です。最後の文字のZは世界協定時を表し、タイムゾーンのプラスマイナスは0になります。

ja.wikipedia.org

日時の規格になるので、他の言語で使用することも可能です。例えばPythonでは3.7以降のバージョンで使用することが出来ます。ただし、先のZの文字がPythonが気に入らないらしく、ここはタイムゾーンを書いてあげる必要があります。うそみてぇ。

from datetime import datetime

iso_string = '2020-03-31T15:00:00.000Z'
iso_string.replace('Z', '+00:00')
iso_string # '2020-03-31T15:00:00.000+00:00'
date = datetime.fromisoformat(iso_string)
print(date) # 2020-03-31 15:00:00+00:00
print(date.day) # 31
print(date.hour) # 15
print(date.year) # 2020

date変数でいろんなdateクラスのメソッドが使えていることがわかると思います。