ぽっけの技術ブログ

仕事や趣味で日々学んだことを出力していきます。

ページの見た目を変える拡張機能なら簡単に作れる

Chrome拡張機能を自作しようと調べると、機能によって3つに分類されるとかJavaScriptファイルを作る必要があるとかいろいろ出てきて尻込みしてしまいますが、ページの見た目をちょっと変えるだけの拡張機能ならCSSの知識があれば簡単に作れます。

サイトの一部を隠したり背景色を変えたりするための最小限の手順をまとめてみました。

ブラウザ:Google ChromeMicrosoft Edge

1. マニフェストファイルを作る(ほぼコピペ)

manifest.jsonという名前のファイルを作成し、メモ帳などで開いて以下を貼り付けます。

{
  "name": "サンプル拡張機能",
  "version": "1.0.0",
  "manifest_version": 3,
  "description": "サンプル拡張機能の説明",
  "content_scripts": [
    {
      "matches": [
        "https://www.google.com/*"
      ],
      "css": [
        "sample.css"
      ]
    }
  ]
}

以下の部分を適当に変えて保存します。

  • name : 拡張機能の名前
  • description : 拡張機能の説明
  • matches : 拡張機能を適用するサイト。例だとhttps://www.google.com/で始まるすべてのページ(=すべてのGoogle検索結果ページ)に適用される。
  • css : CSSのファイル名(これから作ります)

CSSファイルを作る

CSSファイルを作ります。
例:Google検索結果ページのGoogleロゴを非表示にし、背景を少し暗くする。
○○○.css

/*非表示*/
.logo,
.sfbg {
  display: none !important;
}

/*背景を優しい色に*/
.main,
.UK95Uc {
  background-color: rgb(248, 248, 248) !important;
}

セレクタはブラウザのデベロッパーツールで調べるのが楽です。
非表示にしたい要素はセレクタで指定してdisplay: none !important;
背景色を変えたい要素はセレクタで指定してbackground-color: rgb(○○○, ○○○, ○○○) !important;で変えられます。
もちろん他のCSSも適用できます。
!importantをつけることでそのページの本来のCSSよりも優先されます。

拡張機能をブラウザに適用する

上記のmanifest.jsonと○○○.cssを同じフォルダに入れます。

Google Chrome

右上の > その他のツール > 拡張機能 > 右上の「デベロッパー モード」をONにし、「パッケージ化されていない拡張機能を読み込む」クリックしてフォルダを読み込む。

Microsoft Edge

右上の... > 拡張機能 > 拡張機能の管理 > 開発者モードをONにし、フォルダをドラッグアンドドロップ

まとめ

拡張機能の自作について調べると網羅的に書かれた詳しいページがヒットして大変助かるのですが、自分の場合は逆に敷居が高く感じてしまったので、最小限の拡張機能の作り方をまとめてみました。
何かの参考になれば幸いです。

リーダブルコード、解釈と所感

プログラミング初心者~中級者によくおすすめされているリーダブルコードプログラマ歴3年目にして初めて読んだので、自分なりの解釈と所感を書きます。

www.amazon.co.jp

概要

本書はタイトルの通り、読みやすいコードの重要性とそれをどうやって書くかに焦点を当てた技術書です。
他人(未来の自分も含む)から見て読みやすいコードを書くことによって、コードの再利用や保守をやりやすくするのが目的です。

そしてこの本自体が(たぶん意識して)かなり読みやすく書かれています。
文章がすべて口語体だったりたまに挿絵漫画が挟まったり、初学者でもとっつきやすいようかなり工夫がされています。また1章につき平均13ページと短く、集中力を切らさずに一気に理解してしまえる長さに区切られています。
C++JavaScriptPythonなどの具体的なコードを使って解説しています。しかしコードも使い方も簡潔で、プログラミング言語を1つでも触ったことのある人なら十分理解できるようになっています。

解釈

1章

要約:コードを読みやすくすることが大事。(本書のテーマ)。コードを短くすることではない

2章

要約:「パッと見で意味が分かる」を目的に変数名やメソッド名を付ける方法

  • 変数やメソッドには明確な名前を選んで付ける。メソッドGet○○()よりはFetch○○()やDownload○○()など。
  • tmpを小さいスコープの中で使う、イテレータとしてi,j,kを使うのは問題ない。ただしより適した名前があればそれに変えるべき。
for (let i = 0; i < 9; i++) {
  // ループ中の処理
}
  • 間違えるとまずい変数は変数名に付加情報を付けるといい。start_ms(単位がミリ秒であることを強調)、html_utf8(文字コードUTF-8であることを強調)など。
  • 大きいスコープの変数に無理に省略した短い変数名を付けてはいけない。何の略なのかわからなくなるため。
  • 名前のフォーマット(スネークケースやキャメルケース)に情報を持たせることもできる。見ただけでローカル変数かメンバ変数かわかるようになる、などの利点がある。

3章

要約:他の使用者が誤解しないよう気を付けて名前を付ける

  • 限界値を含めるときはmaxやminを使う。
  • 範囲はfirstとlastを使う。
  • 最初を含むが最後は含まない範囲はbeginとendを使う。
  • ブール値の変数名は頭にis・has・can・shouldを使うといい。否定形の変数名はできるだけ使わない。

4章

要約:一貫性のある美しいコードを書こう。プログラミングの時間のほとんどはコードを読む時間だ

  • 同列なものを並べるときは見た目をそろえる。
  • 空行やコメントを使い、段落やブロックに分けて書く。

5章

要約:他人でも理解できるような適切なコメントを書く

  • コメントを付けるより、できるならコメントなしで理解できるコードを書いた方がいい。
  • どんな考えでこのコードを書いたのか、このブロックはどういう意図のコードかなど、他人に理解してもらうためのコメントを書く。

6章

要約:コメントは正確で簡潔に

  • あいまいな言葉を避け短く書く。
  • メソッドの説明のために、引数と返り値の例を記述してもいい。
  • 簡潔に述べるために、「キャッシュ層」「正規化する」など多くの情報を含む言葉を使うといい。

7章

要約:読みやすいように条件分岐やループを組み立てよう

  • 比較(<,>,==など)は左に調査対象の変化する値を置く。
  • if/elseブロックは以下の並び順を参考にすると読みやすくなる。
    • 条件は否定形より肯定形
    • 単純な条件を先に
    • 目立つ条件を先に
  • 三項演算子(条件 ? a : b)はif/elseとどちらが読みやすいか吟味して使う。
  • do/while文はwhile文に書き換えた方が読みやすいことが多い。
  • ガード節で関数の早くから返すのもいい。
  • gotoは基本的に使わない
  • ループのネストを浅く。早めに返したりcontinueを使って改良できる。

8章

要約:人間は同時に多くのものを考えられないので、巨大な式は分割するべき

  • きれいに1行で書くよりも、変数を増やしてでもわかりやすく書いた方がいい。
  • 論理式をド・モルガンの法則で読みやすくできることも。
not (a or b) <=> (not a) and (not b)
not (a and b) <=> (not a) or (not b)
  • 簡単な問題のはずなのにロジックが複雑になってしまったら、発想を転換すべきだ。もっと簡単な方法がある。
  • 巨大な文になってしまったら、共通の式を抜き出して要約変数にしてみる。

9章

要約:変数を工夫してコードを読みやすく

  • 不要な変数は削除。
  • 変数のスコープを小さくすることで、一度に考えなければいけない変数を減らせる。
    • JavaScriptの「クロージャで包む」など、スコープを小さくするためのテクニックを使用する。
    • PythonJavaScriptではブロック内で定義された変数がその関数全体で参照できてしまうので特に注意。
  • 定義は関数やブロックの先頭で行う必要はない。使う直前がいい。
  • 一度だけ書き込む変数はconstやfinalで定義すると考えることを減らせる。

10章

要約:メソッドの目的と関係ない部分を抽出し、別のメソッドとする。(≒無関係の下位問題を抽出する

  • 結果、メソッドには本質的なロジックを扱うコードだけが残る。
  • 大切ではない詳細はユーザーから隠し、大切な詳細は目立つようにする。(14章に書いてあるが、本章の内容に近い)

11章

要約:一度に一つのことを行うようコードを書く

  • 複雑なタスクは整理し、どのようなタスクを組み合わせているかを考え、分割していく。

12章

要約:コードを書くときは、複雑な考えを簡単な言葉で伝えるような意識をもつ

  • ややこしくなってしまったロジックは簡単な言葉で説明してみてから書きなおすといい。自然で簡潔なコードにできる。
  • ラバーダッキングもこれに近い手法。

13章

要約:コードは短いか、何も書かれていない方がいい

  • 書いたコードのテストや保守、文書化などの労力が大きいため。
  • 問題に対して最小の解決法を見つけ出す。
    例:狭い範囲の距離計算機能に、地球の曲率や日付変更線の計算は必要ない。
  • たまに標準ライブラリを読んで把握しておくと、楽な実装を思いつきやすい。

14章

要約:これまでの内容を使い、すっきりと効果的なテストを書こう

  • エラーメッセージはわかりやすく。
  • テスト入力値は綺麗で単純な値を選ぶ。
  • テストに名前を付ける。Test_<関数名> など。
  • 最初からテストしやすいようにコードを書いているといいコードが書ける。クラスやメソッドがよく分割され、グローバル変数が少なくなる。

15章

要約:これまでの内容を使い、時間に関するカウンタを作成する

  • 集大成。これまでの内容(問題の抽出や分割など)を、実際の設計に役立てる様子を筆者が見せてくれる。

所感

読みやすいコードを書く利点や具体的な方法が簡潔に述べられ、全編通して理解しやすかったです。
プログラミングをしていると経験則として身につく「ここはメソッド分けた方がいいな」「分岐条件整理した方がいいな」といったことが理論立てて解説されているので、改めて自分のコーディングを見直すいい機会になりました。
初めてコードを書く方はこれからの指標にできるし、経験者も自分の思考を見直したり悪いクセを矯正したりできる、様々な方にお勧めできる良書でした。

英単語の暗記カードアプリを作成しました

前回の略語暗記カード(略語の暗記カードアプリを作成しました - ぽっけの技術ブログ)を応用し、英単語暗記カードのようなコンソールアプリケーションを作成しました。

TOEIC勉強などに利用できます。

ダウンロード

github.com

使い方

flashcardsForEnglish.pyを実行すると同階層のeng.csvを読み込み、ランダムで英単語を出題します。
Enterで答えが表示されます。
自分が思ったのが合っていたら]Enter
わからなかった、または間違っていたらそのままEnterを押します。
一周するまでわからなかった問題がランダムで出題されます。
また完全に覚えた単語は:Enterすると、次の周回や起動時も二度と出題されなくなります。

<サンプル2>

単語帳ファイルについて

単語帳ファイルeng.cvs(UTF-8、BOM付き)は、[英単語],[日本語訳],[出題フラグ]の形式のCSVファイルです。
サンプルとしてTOEIC~約800点相当の英単語・イディオムを約1400語入れていますが、編集・追記が可能です。
出題フラグが1のもののみが出題され、完全に覚えた単語は出題フラグが0に変わります。

ソースコード

import csv
import random

if __name__ == '__main__':
    while True:
        with open('eng.csv', encoding='UTF-8_sig') as f:
            reader = csv.reader(f)
            l = []
            write = []
            left = 0
            for row in reader:
                if len(row) != 0:
                    l.append(row)
                    write.append(row)
                    if row[2] == '1':
                        left += 1
            
            print('全 ' + str(left) + ' 問')
            print('"]":わかった! ":":覚えた!')
        while True:
            i = random.randint(0, len(l) - 1)
            if l[i][2] != '1':
                continue

            print(l[i][0])
            input()
            print(l[i][1])

            command = input()
            if command.lower() == ']':
                print('  ( -`ω-)✧ わかった!')
                del l[i]
                left -= 1
                print('------------------------残り ' + str(left) + " 問")
            elif command.lower() == ':':
                print('゚+。:.゚ヾ(≧∇≦*)/ 覚えた!.:。+゚')
                left -= 1
                print('------------------------残り ' + str(left) + " 問")

                for row in write:
                    if row[0] == l[i][0]:
                        row[2] = '0'
                        l[i][2] = '0'
                        break
                with open('eng.csv', 'w', encoding='UTF-8_sig', newline='') as f:
                    writer = csv.writer(f)
                    writer.writerows(write)
            else:
                print('◆◆◆◆◆◆◆◆ (・_・)わからん……◆◆◆◆◆◆◆◆')
                print('------------------------')

            if left == 0:
                print('  旦_(-ω- ,,)一周しました。')
                print('')
                break

所感

今回もシンプルな実装とシンプルな機能を目指して作りました。
前回の略語暗記カードを少し改造して英単語暗記カードを作ろうとしましたが、正確に日本語訳を入力しなければならないのは使っていて面倒なので、このような脳内判定形式にしました。
また単語数が1400語以上と膨大になったので、完全に覚えた単語は二度と出題しない機能を付けました。

Pyinstallerでビルドすると重くなるとき

Pyinstallerでpyファイルをexeファイルにビルドすると、ファイルサイズがとても大きくなることがあります。
自分は2KBのpyファイルをビルドすると19943KBのexeファイルになってしまいました。

pyinstaller xxx.py --onefile

pyinstallerで--onefileオプション付きでビルドすると、環境上のライブラリを全て取り込みexeファイルを作成してしまうのが原因です。
対策として不要なライブラリがある場合、--excludeオプションでビルドから除外するライブラリを指定することも出来ます。

ただ、自分は今回乱数生成用のライブラリが必要だったので、 numpy を標準ライブラリの random で代用してみます。

import numpy
# 中略
i = numpy.random.randint(0, len(l))
import random
# 中略
i = random.randint(0, len(l) - 1)

numpy.random.randint()は第1引数以上、第2引数未満の整数をランダムに返すのに対し、
random.randint()は第1引数以上、第2引数以下の整数をランダムに返します。
なので書き換えるときは第2引数の値を1小さくするといいでしょう。

この状態でビルドするとサイズを6498KBまでに抑えることが出来ました。当初の1/3以下です。

所感

作ってpyファイルとして実行するときは軽量だったので何も考えずにnumpyを使いましたが、exe化した後ことも考えてライブラリを選んだ方がよさそうです。
可能なら標準ライブラリを選んだ方が、ファイルサイズを抑えられることがあります。

pyファイルを配布する時はexeファイルにする

先日パソコンAで作成したPythonのソースファイル(.py)を、パソコンBで実行しようとするとうまくいきませんでした。
コンソールアプリだったのですが、一瞬だけコンソールが表示されすぐに終了してしまいます。

Visual Studio Codeで中身を見ると、import numpyの箇所にエラー。
pip list コマンドでライブラリを見てみるとパソコンAにはnumpyがインストールされているのに対し、パソコンBにはインストールされていませんでした。

実行環境にライブラリが足りていなければpyファイルは実行できないようです。
つまりPythonでアプリケーションを作ってもpyファイルは配布するには少し向いていない。

www.insource.co.jp

上記サイトによると配布する時はexeファイルにすると良さそうです。

  1. pyinstallerがなければ pip install pyinstaller でインストール
  2. pyファイルのある階層に移動し、 pyinstaller xxx.py --onefile

これでしばらく待つとdistフォルダが作成され、中にxxx.exeファイルが生成されます。
注意点として、例えばアプリに「同階層のCSVファイルを読み込む」といった操作が含まれる場合、そのままの場所でEXEを実行するとエラーになるのでファイルを移動させましょう。

GitHubで実行ファイルを公開するには?

以前「略語暗記カード」というアプリを作ったのでソースをGitHubに公開しました。

略語の暗記カードアプリを作成しました - ぽっけの技術ブログ

その後「どうせなら実行ファイルも配布しよう」と考えたのですが、よく考えたらGitHubページのどこに置けばいいのかわからなかったので調べてみました。

方法

ソースファイルと同じ場所に置いて公開する……と思っていたのですがそうではなく、GitHubにはRelease機能というアプリケーション配布用の機能が用意されているので、それを使うといいみたいです。

Codeタブ右の Release 内の Create a new release をクリックし、

Choose a tag にバージョン(v1.0.0など)
Release Title にタイトル
Describe this release に説明を書き、
実行ファイルをドラッグアンドドロップして Publish release をクリックします。

Codeタブ右のRelease内にリリースが追加され、実行ファイルがダウンロードできるようになります。

GitHubはソースを共有するためのサービス

GitHubとは、開発プロジェクトのソースコードを管理できるWEBサービスです。 GitHubにはソースコードを共有できる様々な機能があり、プロジェクトのソースコードの管理にかかるコストを削減できます。 https://www.acrovision.jp/career/?p=2930

つまりGitHubは基本的にソースを共有し皆でアプリを開発するための場なので、実行ファイルの配布はソース共有とは別機能になっているみたいです。

略語の暗記カードアプリを作成しました

英語の略語を覚えるための暗記カードのようなコンソールアプリケーションをPythonで作成したので公開します。
ポンポンと問題を解いていけるシンプルなPC用アプリです。
資格勉強なんかに役立ちます。

ダウンロード

github.com

目的

基本情報技術者試験応用情報技術者試験の過去問を解いていると、以下のような問題に出くわします。

WPA3はどれか。
ア. HTTP通信の暗号化規格
イ. TCP/IP通信の暗号化規格
ウ. Webサーバで使用するディジタル証明書の規格
エ. 無線LANのセキュリティ規格
応用情報技術者試験ドットコム 基本情報技術者令和元年秋期 午前問37より

この問題、WPA3が Wi-Fi Protected Access 3 の略であることを知っていれば、それだけで答えが エ. 無線LANのセキュリティ規格 であることがわかります。
このように略語さえ知っていれば答えがわかる問題が結構多かったので、略語を覚えるためのシンプルな暗記カードアプリをPythonで作ってみました。
もちろん単語帳を編集すれば他の勉強にも役立ちます。

使い方

flashcardsForAbbr.pyを実行すると同階層のabbr.csvにある略語がランダムで出題されるので、その略語の省略しない形を答えてEnterを押すと判定されます。
正解ならもうその略語は出題されませんが、不正解ならまた出題されます。
(大文字、小文字は区別されません。)

全て正解するとまた最初からランダムで出題され始めます。このとき単語帳を読み込みなおします。

また回答する代わりに以下のコマンドを入力できます。

コマンド 効果
restart, reset 最初からランダム出題(単語帳を読み込みなおします)
end, finish, quit, exit 終了(普通に×で閉じるのと同じ)

単語帳abbr.csvにはとりあえず私が応用情報技術者試験の勉強に使った単語を入れていますが、好きに変えて使ってください。
形式は[略語],[省略しない形],[解説]です。
文字コードUTF-8なのでExcelだと文字化けします。私はサクラエディタで編集しました。)

ソースコード

flashcardsForAbbr.py

import csv
import numpy

if __name__ == '__main__':
    while True:
        with open('abbr.csv', encoding='UTF-8') as f:
            reader = csv.reader(f)
            l = []
            for row in reader:
                if len(row) != 0:
                    l.append(row)
        while True:
            i = numpy.random.randint(0, len(l))
            print(l[i][0].strip())
            answer = input()
            if answer.lower().strip() == 'restart' or answer.lower().strip() == 'reset':
                break
            if answer.lower().strip() == 'end' or answer.lower().strip() == 'finish' or answer.lower().strip() == 'quit' or answer.lower().strip() == 'exit':
                exit()
            if answer.lower().strip() == l[i][1].lower().strip():
                print('  ヾ(*´∀`*)ノ 正解!')
                print(l[i][0].strip() + ' : ' +l[i][1].strip())
                print(l[i][2].strip())
                print('')
                del l[i]
            else:
                print('◆◆◆◆◆◆◆◆ (・_・)不正解……◆◆◆◆◆◆◆◆')
                print(l[i][0].strip() + ' : ' +l[i][1].strip())
                print(l[i][2].strip())
                print('')

            if len(l) == 0:
                print('  旦_(-ω- ,,)一周しました。')
                print('')
                break

所感

Pythonの勉強も兼ねて作りました。インデントでブロックを作るので見やすいし短く書けてよかったです。
シンプルなコンソールアプリケーションを目指して作りましたが、絵的に寂しくなったので結局顔文字を入れることになりました。
応用情報技術者試験の勉強に実際に使っていますが割と役に立っています。
サンプルのabbr.csvの用語解説が間違ってたらすみません。適当に修正して使ってください。