yucatio@システムエンジニア

趣味で作ったものいろいろ

うっかりミスを防ぐeclipseおすすめ設定6つ【前編】

こんにちは。プログラミングでうっかりミスをしてしまうブログ主です。特にスペルミスがひどいです。 レビューで指摘されると申し訳無い気持ちになるので、そのようなうっかりミスを防止(警告)するeclipseの設定をまとめました。

空白の表示

空白タブ、全角空白、改行文字などを表示するオプションです。

設定 > 一般 > エディター > テキスト・エディター > 空白文字を表示にチェックを入れます。

f:id:yucatio:20200107085812p:plain

次に、可視性の構成をクリックして全てチェックを入れます。

f:id:yucatio:20200107085824p:plain

設定前↓

f:id:yucatio:20200107085900p:plain

設定後↓

f:id:yucatio:20200107085911p:plain

タブは^、スペースは.、全角スペースはで表示されました。改行コードは、LF(Unixの改行コード)は、CRLF(Windowsの改行コード)はで表示されます。

チーム開発時にONにしてほしいオプションナンバー1です。空白とタブを混ぜると後々見にくさの原因になります。

スペルチェック

スペルをチェックをするオプションです。

設定 > 一般 > エディター > テキスト・エディター > スペル > スペル・チェックを使用可能にするにチェックを入れます。

f:id:yucatio:20200107091023p:plain

設定前↓

f:id:yucatio:20200107091117p:plain

設定後↓

f:id:yucatio:20200107091131p:plain

赤の波線が出ている箇所にマウスオーバーすると、修正の候補が表示されます↓

f:id:yucatio:20200107091144p:plain

Javadocのチェック

Javadoc@paramなどの項目がメソッドの定義と一致しているかをチェックするオプションです。リファクタリングのときにJavadocを修正し忘れることはよくあるので入れておきたい設定です。

設定 > Java > コンパイラー > Javadocを開き、以下のような設定にします。

f:id:yucatio:20200107113825p:plain

各設定項目の挙動についてはこちらの記事をご覧ください。

yucatio.hatenablog.com

yucatio.hatenablog.com

設定前↓

f:id:yucatio:20200107113839p:plain

設定後↓

f:id:yucatio:20200107113905p:plain

メソッドで宣言されていないパラメータがJavadocにあると警告を出します↓

f:id:yucatio:20200107113920p:plain

returnに何も記述されていないと警告を出します↓

f:id:yucatio:20200107113931p:plain

存在しないクラスやメソッドを参照すると警告を出します↓

f:id:yucatio:20200107113942p:plain

メソッド宣言にあって、Javadocに無いパラメータがあるときに警告を出します↓

f:id:yucatio:20200107113954p:plain

環境

後編に続く

長くなったので続きます。

yucatio.hatenablog.com

Pythonで辞書が格納されたリストを複数のキーで並べ変える

辞書を格納したリストがある時、複数キーで並び変える方法を紹介します。例えば、以下のような辞書が格納された配列で、まずprice順に並び変え、priceが同じだったら、weightの順番に並び変えたい場合の方法です。

list1 = [
    {'name': 'ぶどう',   'price': 5000, 'weight': 1000},
    {'name': 'もも',     'price': 3000, 'weight': 2000},
    {'name': 'りんご',   'price': 5000, 'weight': 5000},
    {'name': 'バナナ',   'price': 1500, 'weight': 1000},
    {'name': 'メロン',   'price': 5000, 'weight': 1200},
    {'name': 'マンゴー', 'price': 10000, 'weight': 900},
    {'name': 'みかん',  'price': 1500, 'weight': 5000},
]

keyにitemgetterを使用する

辞書の値で並び替える場合、itemgetter関数が便利です。

参考: ソート HOW TO — Python 3.8.1 ドキュメント

itemgetterを使用するときは、 パラメータに辞書のキー名を並び替えの優先順位の順に書きます。

sorted(list, key=itemgetter(第1キー, 第2キー, 第3キー))

まずprice順に並び変え、priceが同じだったら、weightの順番に並び変えたい場合はsorted関数のキーにitemgetter('price', 'weight')を指定します。

コードと並べ替えの結果です。

from operator import itemgetter

# list1は上記のlist1と同様
list1 = [...]

# 並べ替え
sorted_list = sorted(list1, key=itemgetter('price', 'weight'))

# 出力
print(f"{'name':<8}{'price':>8}{'weight':>8}")
print('-' * 24)
for item1 in sorted_list:
    print(f"{item1['name']:<8}{item1['price']:>8}{item1['weight']:>8}")

# name       price  weight
# --------------------------------
# バナナ         1500    1000
# みかん         1500    5000
# もも          3000    2000
# ぶどう         5000    1000
# メロン         5000    1200
# りんご         5000    5000
# マンゴー       10000     900

priceで最初に並べ替え、priceが同じ場合はweightで並び替えられています。デフォルトなのでいずれも昇順で並び替えられています。

keyにlambda関数を使用する

より一般的に複数のキーで並び替えたいときは、keyに指定する関数の戻り値にタプルを指定します。

例えば、グラム単価(price/weight)で並び替えた後、同じグラム単価であれば、priceで並び替えるようなプログラムは以下になります。

# list1は上記のlist1と同様
list1 = [...]

# 並べ替え
sorted_list = sorted(list1, key=lambda item: (item['price'] / item['weight'], item['price']))

# 出力
print(f"{'name':<8}{'price(1g)':>10}{'price':>8}{'weight':>8}")
print('-' * 34)
for item1 in sorted_list:
    print(f"{item1['name']:<8}{item1['price'] / item1['weight']:>10.2f}{item1['price']:>8}{item1['weight']:>8}")

# name     price(1g)   price  weight
# ----------------------------------
# みかん           0.30    1500    5000
# りんご           1.00    5000    5000
# バナナ           1.50    1500    1000
# もも            1.50    3000    2000
# メロン           4.17    5000    1200
# ぶどう           5.00    5000    1000
# マンゴー         11.11   10000     900

グラム単価で並び替えた後、同じグラム単価であれば、priceで並び替えることができました。 マンゴーのグラム単価高いですね。

以上でPythonで辞書が格納されたリストを複数のキーで並べ変えることができました。

環境

htmlのテーブルに使われるタグが覚えられないと思ったときに読む記事

こんにちは。htmlのtable関連タグが覚えられないブログ主です。特に<tr><td>がごちゃごちゃです。が、それぞれの何の英単語の略であるかを覚えたところ、ごちゃごちゃにならずにすみました。今回はそれぞれ何の英語の略なのかと、日本語訳を紹介します。

テーブルの略語タグの略さない名称と日本語での解説

タグ名 何の略か 解説
tr Table Row テーブルの横の行。"row"は"横の行"のこと。
th Table Head テーブルの見出し。"head"は"頭"の意味もありますが、ここでは"見出し"の意味です。
td Table Data テーブルの(個々の)データ。

f:id:yucatio:20200104173533p:plain

rowspanとcolspan

テーブルのセルを結合するrowspanとcolspanも覚えにくいですね。colspanは"column span"の略です。

横の行のことを"row"といい、縦の列を"column"といいます。"row"は"人が並んだ列"の意味もあります。横のイメージですね。"column"は"柱"という意味があります。こちらは縦のイメージですね。

"span"は、"長いスパンで考える"などで使われる"スパン"です。"期間"という意味でも使われますが、htmlの属性では、"(端から端までの)全長"という意味で使用されています。が、全長だと長い方をさす方が多いので、ここでは"太さ"という略語をあてます。

例えば、rowspan="2"であれば、行の太さが2なので、縦に連結されます。

また、colspan="3"であれば、列の太さが3なので、横に連結されます。

f:id:yucatio:20200104173218p:plain

上記テーブルのソースコードはこちらです。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>テーブルタグ確認</title>
    <style type="text/css">
      table {border-collapse: collapse; margin: 40px 20px;}
      th, td {border:1px solid #333; padding: 3px 5px;}
      td.number {text-align:right;}
      thead {background-color: #7fbfff; color: #fff;}
      tfoot {background-color: #eee;}
    </style>
  </head>
  <body>
    <table>
      <thead>
        <tr>
          <th>品名</th><th>単価</th><th>数量</th><th>金額</th><th>消費税</th>
        </tr>
      </thead>
        <tr>
          <td>鉛筆</td><td class="number">30</td><td class="number">12</td><td class="number">360</td><td rowspan="2" class="number">10%</td>
        </tr>
        <tr>
          <td>消しゴム</td><td class="number">50</td><td class="number">6</td><td class="number">300</td>
        </tr>
      <tbody>
      </tbody>
      <tfoot>
        <tr>
          <td colspan="3">合計</td><td class="number">660</td><td></td>
        </tr>
        <tr>
          <td colspan="3">消費税</td><td class="number">66</td><td></td>
        </tr>
        <tr>
          <td colspan="3">合計</td><td class="number">726</td><td></td>
        </tr>
      </tfoot>
    </table>
  </body>
</html>

あとがき

htmlのタグや属性には他にも英語を略したものが使われているので、調べてみると覚えやすくなると思います。

Pythonのconfigparserでセクションがない設定ファイルを(無理矢理)読む

背景

PythonJavaのMANIFEST.MFファイルを読んで表示するプログラムを書く必要がありました。

MANIFEST.MFファイルは以下のような形式です。

Manifest-Version: 1.0
Built-By: yucatio
Build-Jdk: 11.0.5
Created-By: Maven Integration for Eclipse
Implementation-Branch: feature/TOTTEMO_NAGAI_BRANCH_NAME/LONG_SUB_DIRECT
 ORY
Implementation-Build: 1.2.3
  • キー: バリューのようにセミコロンを区切り文字にしている。セミコロンの後には空白が1つ続くが、この空白は値には含まれない。
  • キーの命名規則はChain-Caseで各単語の先頭は大文字
  • 各行は72バイトまでで、それより長くなるときは、改行し行頭に1つ空白を開けてから続きを書く

この形式のファイルをPythonのconfigparserで読んでみます。

コード

ファイルパスを引数にとり、設定内容を辞書型で返すプログラムとその使い方です。

import configparser


def read_config_without_section(config_path):
    """引数に指定されたconfigファイルの内容をdict形式で返す"""
    with open(config_path, 'r') as f:
        # ファイルの内容の先頭に'[dummy_section]'をつける
        config_string = '[dummy_section]\n' + f.read()
    config = configparser.ConfigParser()
    config.read_string(config_string)

    # valueの改行コードを削除
    return {key: value.replace('\n', '') for key, value in config.items('dummy_section', raw=True)}


def main():
    properties = read_config_without_section('/path/to/MANIFEST.MF')

    for key, value in properties.items():
        print(f'{key}:{value}')

# [出力]
# manifest-version:1.0
# built-by:yucatio
# build-jdk:11.0.5
# created-by:Maven Integration for Eclipse
# implementation-branch:feature/TOTTEMO_NAGAI_BRANCH_NAME/LONG_SUB_DIRECTORY
# implementation-build:1.2.3

キーが全て小文字になることに注意が必要ですが、上記のMANIFEST.MFの内容が取得できることがわかりました。

コードの解説

MANIFEST.MFファイルのキーと値を読み込むときに、自前でsplit関数などを使用して自前で読みこむことも考えましたが、configparserのマルチライン機能が便利なのでこちらを使用することにしました。

configparser

configparserの公式ドキュメントはこちらです。使用する際はimportが必要です。

configparser --- 設定ファイルのパーサー — Python 3.7.6 ドキュメント

iniファイル

configparserは iniファイルを読み込むことを想定しています。iniファイルは以下のようにセクションヘッダ([]で囲まれた見出し)とそれに続くkey=valueで構成されます。

iniファイルの例

[Mail]
subject=Sample Mail
mail_from=noreply@yucatio.com

[Log]
log_dir=./log
log_prefix=application
log_rotation=daily

今回読み込もうとするファイルにはセクションヘッダがありません。 セクションヘッダがないファイルを以下のように読み込もうとすると

def read_config_without_section(config_path):
    config = configparser.ConfigParser()
    config.read(config_path)


def main():
    properties = read_config_without_section('/path/to/MANIFEST.MF')

以下のようなエラーが出ます。

# 前略
File "/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/configparser.py", line 1079, in _read
    raise MissingSectionHeaderError(fpname, lineno, line)
configparser.MissingSectionHeaderError: File contains no section headers.
file: '/path/to/MANIFEST.MF', line: 1
'Manifest-Version: 1.0\n'

そこで、ダミーのセクションヘッダをつけます。一旦ファイルの内容を全て読み込み、先頭に[dummy_section]と改行を付けます。

    with open(config_path, 'r') as f:
        # ファイルの内容の先頭に'[dummy_section]'をつける
        config_string = '[dummy_section]\n' + f.read()

configオブジェクトには、read_stringという、文字列を受け取って設定データを読むメソッドがあります。こちらを利用します。

    config = configparser.ConfigParser()
    config.read_string(config_string)

これで、設定が読み込まれました。

キーとバリューの区切り文字

configparserでは、デフォルトでは=または:が区切り文字です。最初に出てきた区切り文字で区切られます。今回はデフォルトのまま使用します。

値のtrim

設定の読み込みの際、キーと値、それぞれの先頭と末尾の空白は取り除かれます。今回はこの性質があるので自分でtrimを書かずに済みました。

マルチライン対応

configparserでは、マルチラインが扱えます。 値の2行目以降は、キーよりも深くインデントする必要があります。幸い、今回読み込むファイルは、2行目が1つの空白でインデントされています。 複数行の値は、読み込まれるとき、2行目以降の先頭の空白は取り除かれ、各行の間には改行コードが入ります。

# 例えば、
key1=value1
  value2
# のとき、key1の値は
# "value1\nvalue2"
# になる(\nは改行を表す)

今回は、値が複数行に渡るときには改行は必要ないので、削除します。

まず、config.items('dummy_section', raw=True)で設定の内容を得ます。このメソッドは、dictのitems()と同様に'dummy_section'セクションの内容をタプルで返します。raw=Trueで変数展開をしないようにします。

タプルの各値をkey, valueで受け取り、value.replace('\n', '')で改行コードを削除しています。

# valueの改行コードを削除
return {key: value.replace('\n', '') for key, value in config.items('dummy_section', raw=True)}

以上でPythonのconfigparserでセクションがない設定ファイルを(無理矢理)読むことができました。

環境

参考

エラーメッセージ内では、"登録できる画像は3つまで"のように"つ"でものを数えてはいけない

仕事で印象に残っている小ネタ。 普段はEC関連のシステムエンジニアをしています。とあるアプリをチームメンバーが改修した時の話です。

改修内容

担当しているサービスで、商品画像の上限枚数を5枚から12枚に変更する改修をしました。 私のチームが担当しているシステムは商品の登録システムでした。ストレージの見積もり等の作業はありますが、 ソースコードの改修は枚数の上限値を変更するだけの簡単なものです。

変更内容

エラーメッセージはファイルに記載されています。こんな感じで変数を埋め込めるようになっています。(実際のものとは違います)

登録できる画像は{MAX_IMAGE}つまでです

ソースコードの改修もこの部分だけでした。

-MAX_IMAGE=5
+MAX_IMAGE=12

テスト

一応テストケースも確認しておきましょう。

-登録できる画像は5つまでです
+登録できる画像は12つまでです

5が12になってる。大丈夫、って"12つ"ってなんだ!?そんな日本語あったっけ?いや、ない。あれ?

1つ、2つ、3つ、4つ、5つ、6つ、7つ、8つ、9つ

うん、ここまでは聞いたことある。

10つ

いや、"じゅっつ"なんて日本語は聞いたことがないぞ。"とお"だろう、ここは。

11つ、12つ

これもないはず。あってるよね?と思ってググってみた。

つ: 1から9までのものに対してつける。10は「とお」で「つ」をつけない。11以上は助数詞「個」などを使う。

wikipediaより

https://ja.wikipedia.org/wiki/%E5%8A%A9%E6%95%B0%E8%A9%9E

大丈夫だ。自分の感じたことがあってる。

というわけで、"つ"を他の言葉に変えなければいけないのだけれども、画像ってなんて数えるのだろう?"個"?"枚"?

がぞう【画像】

一枚(いちまい)、一点(いってん)

https://www.sanabo.com/kazoekata/ct_ka/ka/gazou/

というわけでこの時は"枚"で数えるように変更しました。

このとき、ソースコード改修を担当していたのは日本語ネイティブでないメンバーでした。そりゃ気づけないよね。

こんなことがあったのでちょっとバタバタしましたがリリースは予定通りうまく行きました。

正直テストコードに助けられました。変な日本語でリリースしなくてよかった。

教訓

エラーメッセージ内で何かを数えるとき、単位(助数詞)に"つ"を使わない。

JavaScript Ruby Pythonで文字列中に変数を展開できる機能の名前と書き方

こんにちは。JavaScriptRubyPythonが頭の中でごちゃごちゃになっているブログ主です。

JavaScriptRubyPythonの文字列中に変数を展開できる機能の名前と書き方が頭の中でごちゃごちゃです。 RubyなのにJavaScriptの記法で書いてしまい、なぜ思った通りに表示されないのか悩んだことも1度ではありません。そんな自分のためにそれぞれの言語での文字列中に変数を展開できる機能の名前と書き方をまとめました。

環境

動作を確認したバージョンです。

JavaScript

日本語名 テンプレート文字列
英語名 Template literals (Template strings)
コード例
a = 1
b = 2
// ${式} を使用する
str = `${a}たす${b}は${a + b}です。`
// 1たす2は3です。

Ruby

日本語名 式展開
英語名 Interpolation
コード例
a = 1
b = 2
# #{式} を使用する
str = "#{a}たす#{b}#{a + b}です。"
# 1たす2は3です。

Python

日本語名 フォーマット済み文字列リテラル(f-string)
英語名 Formatted string literals(f-string)
コード例
a = 1
b = 2
# f'{式}'
str1 = f'{a}たす{b}は{a + b}です。'
# 1たす2は3です。

JavaScript Ruby Pythonの配列やキーバリュー要素を展開したり多重代入したりする操作の名前と記号

こんにちは。JavaScriptRubyPythonが頭の中でごちゃごちゃになっているブログ主です。

JavaScriptRubyPythonの配列とキーバリューオブジェクトが頭の中でごちゃごちゃです。ググろうとしても、「あの、アスタリスクつける操作、なんだっけ」となり、やりたいことをググる以前に操作の名前をググる必要があり、その際記号だと検索に引っかかりづらいため、かなり時間を取られます。 そんな自分のために、配列とキーバリューオブジェクトの記号を使った展開や代入の操作をまとめました。

配列とキーバリューオブジェクトの各言語での呼び名

配列とキーバリューオブジェクトの各言語での呼び名です。 配列とは何か、キーバリューオブジェクトとは何かの定義はしないので、以下を見てなんとなく理解してください。

JavaScript Ruby Python
配列 配列(Array) 配列(Array) リスト(list)
キーバリュー ハッシュ(Hash) オブジェクト(Object) 辞書(dictionary)

環境

動作を確認したバージョンです。

配列とキーバリューオブジェクトの各言語での記号を使用した展開や代入の名前とサンプルコード

配列とキーバリューオブジェクトの、各言語での記号を使用した展開や代入の名前とサンプルコードです。 サンプルコードは代表的な使用法に限りました。名前が分かれば細かい部分は検索が可能と思いますので。 各言語、細かい違いがありますので、使用の際には公式ページをご覧ください。名称に公式ページへのリンクが張ってあります。

配列の要素を一度に複数の変数に代入する

JavaScript Ruby Python
日本語名 分割代入 多重代入 シーケンスのアンパック
英語名 Destructuring assignment Multiple assignment
Array Decomposition
Sequence unpacking
コード例
const arr = [1, 2]
const [a, b] = arr
// a=1, b=2
arr = [1, 2]
a, b = arr
# a=1, b=2
my_list = [1, 2]
a, b = my_list
# a=1, b=2
備考

キーバリューの要素を一度に複数の変数に代入する

JavaScript Ruby Python
日本語名 分割代入 (該当なし) (該当なし)
英語名 Destructuring assignment - -
コード例
const obj = {a: 1, b: 2}
const {a, b} = obj
// a=1, b=2
- -
備考 メソッドの引数でも使用できる。キーワード引数の代替になる。 引数を受け取る場面ではキーワード引数が利用可能 引数を受け取る場面ではキーワード引数が利用可能

配列を展開してメソッドの引数にする

JavaScript Ruby Python
日本語名 スプレッド構文 配列展開*1 アンパック
英語名 Spread syntax Splat operator Unpacking
コード例
const myFunction = (a, b) => {
  console.log(`a:${a}, b:${b}`)
}
const arr = [1, 2]
myFunction(...arr)
// a:1, b:2
def my_function(a, b)
  puts "a:#{a}, b:#{b}"
end
arr = [1, 2]
my_function(*arr)
# a:1, b:2
def my_function(a, b):
    print(f'a:{a}, b:{b}')
my_list = [1, 2]
my_function(*my_list)
# a:1, b:2
備考 配列展開に使用される"*"をsplat operatorという 配列展開に使用される"*"をstar operatorという

オブジェクトを展開してメソッドの引数にする(キーワード引数)

JavaScript Ruby Python
日本語名 (該当なし) (不明)*2
(ハッシュ展開*3 )
アンパック
英語名 - Double splat operator Unpacking
コード例 -
def my_method(a:, b:)
  puts "a:#{a}, b:#{b}"
end
my_hash = { a: 1, b: 2 }
my_method(**my_hash)
# a:1, b:2
def my_function(*, a, b):
    print(f'a:{a}, b:{b}')
my_dict = {'a': 1, 'b': 2}
my_function(**my_dict)
# a:1, b:1
備考 分割代入を使用して、キーワード引数に似た機能を使用できる
const myFunction = ({a, b}) => {
  console.log(`a:${a}, b:${b}`)
}
const obj = {a: 1, b: 2}
myFunction(obj)
// a:1, b:2
"**"をつけなくても動くが、つけるのが推奨されている。

配列を展開して配列を結合する(ときに記号を使った書き方)

いずれも2つの配列を結合して新たな配列を作ります。もとの配列は変化しません。

JavaScript Ruby Python
日本語名 スプレッド構文 Array#+ 加算演算子
英語名 Spread syntax Array#+ addition operator
コード例
arr1 = [1, 2]
arr2 = [3, 4]
arr3 = [...arr1, ...arr2]
// [1, 2, 3, 4]
arr1 = [1, 2]
arr2 = [3, 4]
arr3 = arr1 + arr2
# [1, 2, 3, 4]
list1 = [1, 2]
list2 = [3, 4]
list3 = list1 + list2
# [1, 2, 3, 4]
備考

キーバリューを展開してキーバリューを結合する(ときに記号を使った書き方)

いずれも2つのキーバリューオブジェクトを結合して新たなキーバリューオブジェクトを作ります。もとのキーバリューオブジェクトは変化しません。

JavaScript Ruby Python
日本語名 スプレッド構文 (不明)*4
(ハッシュ展開*5 )
アンパック
英語名 Spread syntax Double splat operator Unpacking
コード例
obj1 = {a: 1, b: 2}
obj2 = {c: 3, d: 4}
obj3 = {...obj1, ...obj2}
// {a: 1, b: 2, c: 3, d: 4}
hash1 = {a: 1, b: 2}
hash2 = {c: 3, d: 4}
hash3 = {**hash1, **hash2}
# {:a=>1, :b=>2, :c=>3, :d=>4}
dict1 = {'a': 1, 'b': 2}
dict2 = {'c': 3, 'd': 4}
dict3 = {**dict1, **dict2}
# {'a': 1, 'b': 2, 'c': 3, 'd': 4}
備考

あとがき

配列、キーバリュー周りに関しては、意外とRubyPythonの記法が似ていました。キーワード引数については、Pythonの記法をRubyでも使えるようにしたものだそうです。

配列もキーバリューのオブジェクトの名前も、それらに関する操作の名前ももっと言語間で統一してくれたらいいのにな、と思いました。 新しい言語を作る時には新しい名前を付けたくなるのかも。

*1:配列展開というのが正式名称ではなく、「引数の直前に * がついている場合、その引数の値が展開されて渡されます。」という記述から配列展開という言葉を使用しています

*2:日本語の公式ページに記載が見つけられませんでした。情報求めます

*3:配列展開の転用。個人ブログでこのように呼んでいるケースもあります

*4:同上

*5:同上