20201020のMacに関する記事は6件です。

[day: 3]小さな効率化とリーダブルコード

小さな効率化とリーダブルコード

はじめに

2020/4/1にエンジニアになりました。
scala/Play、TypeScript/Angular
ほぼ日記みたいな内容です。
毎日の学習のアウトプットが目的です。

小さな効率化

小さいですが、積み重なると大きい効率化をしました。
それはHotKeyを利用してiTerm2を開くことです。
今までは別の画面からiTerm2を開くときにはcommand + tabを使って切り替えてました。
キーボードのホームポジションから大きく左手がずれてしまうのと、タブでの選択を間違えてしまうと大きく時間をロスしてしまいます。
ショートカットでHotKeyを設定すると一瞬で今いる画面の上に被さる形でiTerm2を表示できるので、調べ物から開発に切り替える際の動きが格段に早くなりました。
自分はoption + enterで設定しています。
おすすめなので皆さんも試して見てはいかがでしょうか。

参考にした記事
iTerm2のおすすめ設定〜ターミナル作業を効率化する〜

リーダブルコード

リーダブルコードを読みましたので、簡単にまとめたいと思います。
リーダブルコード――より良いコードを書くためのシンプルで実践的なテクニック

1章 理解しやすいコード

  • コードは他人にとって理解しやすく書く
  • コードは他人が最短時間で理解できるように書く
  • 理解する時間が短い > コードが短い
  • このコードは見やすいか確認する

2章 名前位に情報を詰め込む

  • 名前に情報を詰め込む
  • 名前は小さなコメントである
  • 明確な単語を選ぶ
    • 適格な意味を持つ単語を選択する
    • シソーラスで検索して調べる
    • 気取った言い回しよりも正確で明確な単語を選ぶ
  • 汎用的な名前を避ける 例)tmpやretval
    • 情報の保存期間が一瞬であれば汎用的で良い
  • 抽象的な名前よりも具体的な名前を使う
    • 変数名が抽象的だと使用者によって解釈が異なる
      • 何をするのか明確にわかる名前をつける
  • 名前に情報を追加する
    • 絶対に伝えたい情報は名前に入れる
    • 単位など
  • 名前の長さを決める
    • 名前は長すぎないようにする
    • スコープの範囲が短い場合には短くても良い
      • 理解しにくい省略形の名前はつけない
  • 名前のフォーマットで情報を伝える
    • クラスや変数で使用するフォーマットを変えると読みやすくなる
    • プロジェクトでの一貫性が大事

3章 誤解されない名前

  • 他人が違う意味に誤解しないか確認する
  • 否定形を避ける

4章 美しさ

  • 優れたコードは目に優しいものである
  • 似ているコードは似ているように書く
  • インデントを揃えて縦の線を真っ直ぐにする
  • コードを段落に落とし込む

5章 コメントすべきことを知る

  • コメントの目的は書き手の意図を読み手に知らせることである
  • コメントを読んだ方が理解がはやか?
  • 優れたコード > ひどいコード+コメント
  • 変数名を変えることでコメントが不要にならないか考える
  • プログラマーが使う典型的な意味 -TODO:後で手をつける
    • FIXME:既知の不具合があるコード
    • HACK:あまりキレイじゃない解決法
    • XXX:危険!大きな問題がある
  • 質問されそうな箇所を考える
    • 新しく入ったメンバーが理解に時間がかかる箇所などを考える
  • 巨大な関数の流れをコメントで把握できるようにする

6章 コメントは正確で簡潔に

  • コメントは簡潔に
  • 曖昧な代名詞を避ける
  • 小さな領域に情報を詰め込む

7章 制御フローを読みやすくする

  • 条件式の引数の並び順
    • 左;変化する、右;変化しない
  • if文の記述
    • 肯定系を優先して使う
    • 単純な処理を先に書く
    • 目立たせたい処理を先に書く
  • ネストを浅くする

8章 巨大な式を分解する

  • 説明変数:式の意味を説明する
  • 要約変数:式の内容を小さく分割できる、その式の内容を要約している

9章 変数と読みやすさ

  • 不要な変数を削除する
    • 変数が減るとコードは簡潔になる
    • 本当にその変数が必要か確認する
  • 変数のコードを縮める
    • グローバルな変数は削除する

10章 無関係な下位問題を抽出する

  • 汎用的なコードを作成する
  • 高レベルの解決に集中する
    • 下位問題は分解して抽出する

11章 1度に一つのことを

  • 2つ以上のことを行っているコードは分解する
  • ヘルパーメソッドを利用する
    • ヘルパーメソッドとは他の関数に依存することなくある特定の処理を行うメソッド

12章 コードに思いを込める

  • 簡単にわかりやすく説明できなければ理解したとは言えない
    • おばあちゃんにも理解できるように説明できますか?
    • コードの動作を同僚に簡単な言葉で説明してみる
    • 説明の中で使用したキーワードやフレーズに注目する
    • その説明に合わせてコードを書く

13章 短いコードを書く

  • ライブラリが何を提供しているのかを知る
    • 普段使用しているライブラリの提供しているものを定期的にじっくり見てみる
    • 標準ライブラリで解決できる問題があることがある
  • 今書いているそれらのコードは本当に必要か?
  • 1日にエンジニアが出荷するコードは10行である
  • 不要な機能はプロダクトから削除する
    • メモリの消費を抑える
  • 過剰な機能はもたせない
  • 最も簡単に問題を解決する方法を考える

最後に

  • 実際にやる
  • 当たり前にする
  • コードでつたる

毎日投稿について

  • 完全な自己満足
  • アウトプットの習慣づけ
  • インプットした内容の記憶の定着を促進
  • 継続 > クオリティ
  • 昨日の自分より成長している実感を得る
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PDF(SBI証券、くりっく株365、取引残高報告書)からCSV(テキスト)を作成する

はじめに

世界の株価指数に投資することが出来る金融商品として、
くりっく株365があります。

上場CFD(東京金融取引所に上場する株価指数証拠金取引)ですが、
 個人だと申告分離課税、
 法人だと法人税と、
確定申告をしなければなりません。

年1回、取引残高報告書に基づいて申告する
のですが、
SBI証券の場合、PDFなのですよ。

これを手作業で集計するのが面倒なので、

PDF、取引残高報告書のうち(2頁〜)証拠金入出金明細書を
CSV(テキスト)にします。

これを会計ソフトと税務ソフト(eTaxの①預貯金)反映させることを目的としています。

注意点

テスト不足です。
・複数頁にまたがる場合は、どうだろう。。
・未使用と思われる列にデータがあると、誤動作するでしょう。

想定PDF

7列の表ですが、
摘要(3列)と備考(7列)にはデータが無いと想定しています。

2020-10-20 18.39のイメージ.jpeg

使い方

使い方.R
source( "PDF_CFD_SBI.R" ) 
    # PDFのあるディレクトリーを指定
d <- file.path( ... ,"B_0988_SBI証券" ,"CFD" )

出入 <- CFD.main( d )

PDF_CFD_SBI.R
    # pdfデータをインポートするため
library( pdftools ) # install.packages( 'pdftools'  )

CFD.main <- function( d ) {
        print( d )
    CFD <- CFD.init()   # ファイル別
    files   <- dir( d ,pattern=".pdf$" ,ignore.case=T )
    for( f in files) {
        p <- pdf_info( file.path( d ,f ) )$pages
        df <-   pdf_data( file.path( d ,f ) )
            print( c( f , p ) )
        CFD <- rbind( CFD ,CFD.pdf( df ,p ) )
    }   
return( CFD.fin( CFD ) )
}
print( c( "CFD.main()" ,CFD.main ) )

CFD.pdf <- function( df ,p ) {
    CFD <- CFD.init()   # PDF別
    for( i in 1:p ) {  # i <- 2
        print( i )
        df_p <- sapply( df[[ i ]] ,"[" )  [ ,c("x","y","text") ]  
        x <- as.integer( df_p[ ,"x" ] )
        y <- as.integer( df_p[ ,"y" ] )

        h1 <- subset( df_p ,df_p[,"text"] == "証拠金入出金明細書" )
        h1_y <- as.integer( h1[,"y"] )
        if ( nrow( h1 ) == 0 ) next
        print( h1 )

        h2 <- subset( df_p ,df_p[,"text"] == "受渡日" )
        h2_y <- as.integer( h2[,"y"] )
        m <- df_p[ y > h2_y , ]
        r <- subset( m, m[ ,"x"] == 25 )
        CFD <- CFD.line( m ,r )
    }
return( CFD )
}
print( c( "CFD.pdf()" ,CFD.pdf ) )

CFD.line <- function( m ,r ) {
    CFD <- CFD.init()   
    for( j in 1:nrow( r ) ) {  
        CFD[ j ,1 ] <- r[ j,"text"] 
         <- subset( m ,m[ ,"y" ]==r[ j , "y" ] )
        CFD[ j ,2 ] <- [ 2,"text"]   
        if( as.integer( [ 3,"x"] ) <= 488 ) {
            CFD[ j ,4 ] <- [ 3,"text"]
        } else {
            CFD[ j ,5 ] <- [ 3,"text"]
        }   
        CFD[ j ,6 ] <- [ 4,"text"]
            # 想定外かも?
        switch( ( nrow(  ) - 4 ) 
        ,"1" = {
            print(  ) 
            }   
        )
    }
return( CFD )
}
print( c( "CFD.line()" ,CFD.line ) )

CFD.fin <- function( 出入 ) {
    出入[ ,1] <- gsub( "/" ,"-" ,出入[ ,1] )
    出入[ ,4] <- as.integer( gsub( "," ,"" ,出入[ ,4] ) )
    出入[ ,5] <- as.integer( gsub( "," ,"" ,出入[ ,5] ) )
    出入[ ,6] <- as.integer( gsub( "," ,"" ,出入[ ,6] ) )
return( 出入 )
}
print( c( "CFD.fin()" ,CFD.fin ) )

CFD.init <- function( n=1 ) {
            # 列数
    df <- data.frame( matrix( NA ,0 ,7 ) )
            # 列名
    colnames( df ) <- c(
     "受渡日="           # 列1
    ,"区分="      # 列2
    ,"摘要="          # 列3
    ,"証拠金の減少="   #,"証拠金の減少(円)="       # 列4
    ,"証拠金の増加=" #,"証拠金の残高(円)="     # 列5
    ,"証拠金の残高="   #,"証拠金の残高(円)="       # 列6
    ,"備考="      # 列7
    )
    switch( n
    , "1" =  {      # (2頁〜)証拠金入出金明細書
        #   print( sapply( df ,mode ) )
        }
    )
return( df )
}
print( c( "CFD.init()" ,CFD.init ) )
#
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コマンドラインから日本化粧品工業連合会の成分表示名称リスト検索するのに使ったツールたち。

コマンドラインから日本化粧品工業連合会の成分表示名称リスト検索するのに使ったツールたち。

化粧品の輸入をする場合INCI名で書かれた成分リストを日本語のものに変換する作業が絶対に必要になる。日本化粧品工業連合会のWEBで検索してポチポチとやっていたのだが、めんどくさくなったのでコマンドライン から作業した時の記録。

前提条件

  • mac
  • zsh
  • xmllint
  • sed
  • mktemp

作ったfunction

  • chochodo_search_from_jcia [SEACH_WORDS]: 緩やかな検索用(xml取得)
  • chochodo_search_from_jcia_by_inci [INCI_NAME]: スタティックな検索用(xml取得)
  • chochodo_get_data_by_inci [INCI_NAME]: INCI名から「INCI名,表示名称,No,INCI名(検索結果)」のカンマ区切りを得る
  • chochodo_trim [STRING]: 前後のトリム(って言わないの?)
  • chochodo_get_inci_csv [FILE_PATH] : INCI名のリスト(1行に1INCI名が入ったテキストファイル)を順に検索していって、INCI名と表示名称の入ったcsvを出力する

ファイルへの書き込みはchochodo_get_inci_csv 中でmktempを使った場所のみなので心が苦しくならない。

function chochodo_search_from_jcia(){

  if test -z $1 ; then
    echo "usage  : chochodo_search_from_jcia [SEARCH_WORDS]"
    echo "ex) chochodo_search_from_jcia BG"
    return
  fi
  (
  PHPSESSID=$(curl 'https://www.jcia.org/user/business/ingredients/search' \
    -H 'Connection: keep-alive' \
    -H 'Accept: */*' \
    -H 'X-Requested-With: XMLHttpRequest' \
    -H 'sec-ch-ua-mobile: ?0' \
    -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
    -H 'Origin: https://www.jcia.org' \
    -H 'Sec-Fetch-Site: same-origin' \
    -H 'Sec-Fetch-Mode: cors' \
    -H 'Sec-Fetch-Dest: empty' \
    -H 'Referer: https://www.jcia.org/user/business/ingredients/namelist' \
    -H 'Accept-Language: ja,en-US;q=0.9,en;q=0.8' \
    --data-raw 'search%5Bfreeword%5D='"$1" \
    --compressed -i | grep 'Set-Cookie: PHPSESSID=' | cut -d '='  -f2 | cut -d ';' -f1)

   curl 'https://www.jcia.org/user/business/ingredients/list/page/0' \
        -H 'Connection: keep-alive' \
        -H 'Accept: text/plain, */*; q=0.01' \
        -H 'sec-ch-ua-mobile: ?0' \
        -H 'X-Requested-With: XMLHttpRequest' \
        -H 'Sec-Fetch-Site: same-origin' \
        -H 'Sec-Fetch-Mode: cors' \
        -H 'Sec-Fetch-Dest: empty' \
        -H 'Referer: https://www.jcia.org/user/business/ingredients/namelist' \
        -H 'Accept-Language: ja,en-US;q=0.9,en;q=0.8' \
        -H 'Cookie: PHPSESSID='$PHPSESSID';' \
        --compressed | xmllint --encode utf8 --noblanks -
    )
  }


function chochodo_search_from_jcia_by_inci(){

  if test -z $1 ; then
    echo "usage  : chochodo_search_from_jcia_by_inci [INCI_NAME]"
    echo "ex) chochodo_search_from_jcia_by_inci BG"
    return
  fi
  (
  chochodo_search_from_jcia '@'"$1"
  )
  }

function chochodo_get_data_by_inci(){
(
 INCI_NAME_FROM_FILE=$1
 RESULT_XML=$(chochodo_search_from_jcia_by_inci $INCI_NAME_FROM_FILE)
 ROW=$(echo $RESULT_XML|xmllint --xpath '/return_data/rows/row[1]' - |xmllint --encode utf8 --noblanks -)
 NAME=$(chochodo_trim "$(echo $ROW|head -5| tail -1 )")
 NO=$(chochodo_trim "$(echo $ROW|head -3| tail -1 )") 
 INCI_NAME=$(chochodo_trim "$(echo $ROW|head -7| tail -1 )")

 echo '"'$INCI_NAME_FROM_FILE'","'$NAME'","'$NO'","'$INCI_NAME'"'
)

}

function chochodo_trim(){
(echo $1|sed 's/^[[:blank:]]*//'|sed 's/[[:blank:]]*$//')
}

function chochodo_get_inci_csv(){
(
FILE_NAME=$1
CSV_FILE_NAME=$(mktemp)
echo "INCI_NAME_FROM_FILE,NAME,NO,INCI_NAME" >$CSV_FILE_NAME
while read INCI_NAME
do

  echo $(chochodo_get_data_by_inci "$(trim $INCI_NAME)") >> $CSV_FILE_NAME
done < $FILE_NAME
cat $CSV_FILE_NAME
rm $CSV_FILE_NAME
)
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

brew install mtr macOS10.15

homebrewでmtrを導入したらパスが通っていなかったメモ

結論だけ知りたい方は、まとめ参照

homebrewでmtrをインストール

% brew install mtr
|
|
?  /usr/local/Cellar/mtr/0.94
mtr requires root privileges so you will need to run `sudo mtr`.
You should be certain that you trust any software you grant root privileges.

8.8.8.8に向けてmtrを実行したが、mtrがないらしい

% sudo mtr 8.8.8.8
Password:
sudo: mtr: command not found

パスを見てみると、/usr/local/Cellar/mtr/0.94らしい。

~ % brew link mtr
Warning: Already linked: /usr/local/Cellar/mtr/0.94
To relink:
  brew unlink mtr && brew link mtr

中身を見てみると、それっぽいのがない

% ls /usr/local/Cellar/mtr/0.94
AUTHORS         INSTALL_RECEIPT.json    README.md       sbin
COPYING         NEWS            TODO            share

こっちにあった。

% ls /usr/local/Cellar/mtr/0.94/sbin
mtr     mtr-packet

リンク作成①

% ln /usr/local/Cellar/mtr/0.94/sbin/mtr /usr/local/bin/mtr

再度実行すると、mtr-packetもいるらしい

% sudo mtr 8.8.8.8
mtr: Failure to start mtr-packet: Invalid argument

リンク作成②

% ln /usr/local/Cellar/mtr/0.94/sbin/mtr-packet /usr/local/bin/mtr-packet

もっかい実行、動いた

                               My traceroute  [v0.94]
xxxxx-MacBook-Pro.local (172.31.xxx.xxx) -> 8.8.8.8        2020-10-15T23:41:13+0900
Keys:  Help   Display mode   Restart statistics   Order of fields   quit
                                            Packets               Pings
 Host                                     Loss%   Snt   Last   Avg  Best  Wrst StDev
 1. 172.31.xxx.xxx                         0.0%     5    1.7   3.3   1.7   9.4   3.4
 2. 10.255.xxx.xxx                         0.0%     5    2.0   3.2   1.9   8.0   2.7
 3. xxxxxxxxxxxxxxx.ppp-bb.dion.ne.jp      0.0%     5    4.2   3.8   3.4   4.2   0.3
 4. xxxxxxxxxxxx.bb.kddi.ne.jp             0.0%     5    6.4   5.5   5.0   6.4   0.5
 5. xxxxxxxxx.bb.kddi.ne.jp                0.0%     5   16.5   8.3   5.1  16.5   4.7
 6. 27.85.xxx.xx                           0.0%     5    9.3   9.8   7.1  17.1   4.2
 7. 27.85.xxx.xx                           0.0%     5    9.7   8.4   6.2  13.3   3.1
 8. 72.14.xxx.xx                           0.0%     5    7.1   9.5   6.2  13.9   3.5
 9. 209.85.xxx.xx                          0.0%     5    5.7   6.4   5.7   7.7   0.8
10. 72.14.xxx.xxx                          0.0%     4    5.9   8.5   5.9  12.9   3.2
11. dns.google                             0.0%     4    6.3   6.7   5.7   8.0   1.0                                                                                                                                       

まとめ

% brew install mtr
% ln /usr/local/Cellar/mtr/0.94/sbin/mtr /usr/local/bin/mtr
% ln /usr/local/Cellar/mtr/0.94/sbin/mtr-packet /usr/local/bin/mtr-packet

以上

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

macでsshpassをインストールする

個人用メモ

# 普通に
brew install sshpass

# ダメでした
# urlから
brew install https://raw.githubusercontent.com/kadwanev/bigboybrew/master/Library/Formula/sshpass.rb

#これもダメ

brew install hudochenkov/sshpass/sshpass
# めでたし
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】iterdir()など使用時に出る[Errno 20] Not a directory: '***/.DS_Store'

Pythonでiterdir()などを使うと、タイトルのようなエラーが出てきます。
Mac独自の.DS_Storeという隠しファイルのせいで、関数が実行できない時出てきます。
対処としては、.DS_Storeを消せば良いだけです。

そもそも.DS_Storeとは

.DS_Store は、Finderがフォルダの設定を記録するためのファイルです。
参考サイト

対処

ファインダーでもコマンドラインでもいいので消します。

コマンドラインの場合、
邪魔な.DS_Storeが入っているフォルダに移動し

find . -name ".DS_Store" -delete

で消します。
参考サイト

終了です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む