[Python] 322 ファイルの文字コードを一括変換

[Mac mini M1(2020), macOS Big Sur 11.6.1, Python 3.10.0]

Javaに関する基本的な知識を整理するため、”オラクル認定資格教科書 Javaプログラマ Silver SE11″を購入しました。Amazonセール半額の2090円だったので思わずポチりました。

例によってサンプルコードの文字コードがShift-JISのため、Macで読めるようUTF-8に一括変換しました。

まずサンプルコードのフォルダをコピーしフォルダ名を変更。自製アプリでディレクトリ構造を残したままファイルを全消去しました。そして以下の一括変換コードを実行しました。

ちなみにファイルを消さずに上書きになるようnkfコマンドを実行すると0バイトの空ファイルになります。

UTF-8からShift-JISへ変換する場合のコマンドは”nkf -s”になります。nkfはコマンド”brew install nkf”で前もってインストールしておきます。

JavaでしたらPathオブジェクトを文字列に変換する必要があるのですが、Pythonは不要なのでとても楽ですね。動的型付けのいいところです。

昨年9月に書いた変換先のフォルダ作成を含めたコードをよりシンプルにしました。

import glob,subprocess

dir = "/JavaSilver_samplecode"
paths_sjis = glob.glob(dir + "/**/*.java", recursive=True)

print(paths_sjis)

# 変換ファイルパス作成(フォルダ名を変更しファイル名はそのまま)
paths_utf8 = list()
for path in paths_sjis:
    path_utf8 = path.replace("JavaSilver_samplecode","JavaSilver_samplecode_utf8")
    paths_utf8.append(path_utf8)
    
print(paths_utf8)

for a,b in zip(paths_sjis,paths_utf8):
    cmd = "nkf -w %s > %s" %(a,b)
    subprocess.call(cmd, shell=True)

[Java] 86 jar実行ファイルの作成

# ソースコードのディレクトリに移動する
cd /projects/FileRemover/src

# ソースコードをJavaバイトコードにコンパイルする
javac App.java

# jar実行ファイルを作成する
jar cvfm FileRemover.jar manifest.mf *.class

# manifest.mfの内容(必ず改行する)
Main-Class: App

# jarを実行(ダブルクリックも可)
java -jar FileRemover.jar

[macOS] 34 launchdによる定期実行 実施例

[macOS Big Sur 11.6.1]

launchdによるプログラムの定期実行を試してみました。

エディタやXcodeを使ってxml形式でplistファイルを作成するのですが、エディタでは非常に書きにくいです。Xcodeが多少マシかと思います。どちらにしても結局crontabの方が扱いやすいです。

plistファイルを/Library/LaunchAgentsに作成したら、chownコマンドで所有者変更、chmodコマンドで権限変更します。最後にplistファイルをロードすると定期実行が始まります。

下記コード例では60秒おきにtest.pyを実行します。

このスキルはcrontabが使えなくなった際の代替手段としてストックしておきます。htmlとxmlは極力書きたくないです。だからなのかJavaScriptとはまた疎遠になっています。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>test</string>
    <key>ProgramArguments</key>
    <array>
        <string>python</string>
        <string>test.py</string>
    </array>
    <key>StartInterval</key>
    <integer>60</integer>
    <key>StandardOutPath</key>
    <string>test.out</string>
    <key>StandardErrorPath</key>
    <string>test.err</string>
</dict>
</plist>
Xcodeでplistを表示
# plistを有効化
launchctl load test.plist

# plistを無効化
launchctl unload test.plist

[macOS] 33 launchdによる定期実行検討

[macOS Big Sur 11.6.1]

前回記事でMicrosoft AutoUpdateの定期実行を強引にできなくしましたが、そもそもどこで管理しているのか調べてみました。

今回のケースではライブラリディレクトリにあるLaunchAgentsやLaunchDaemonsでコントロールしています。crontabだけではなくこのlaunchdというサービス管理フレームワークでも自由にプログラムの定期実行を設定できるようです。

Microsoftの他にCubaseのメーカーであるSteinbergやフリーソフトKarabinerのプロパティリストファイルがありました。知らぬ間に放り込まれているので監視が必要ですね。ここに名を連ねるアプリは曲者という印象です。

ちなみにplistファイルは基本的にはXcodeで編集可能なはずですが、RunAtLoadの設定をNOにすることはできませんでした。ファイルの権限を変えても不可でした。どうやらファイルごと消去するしかないようです。

次回以降でlaunchdを使った定期実行を試してみます。

2021/11/20追記:plistファイルを編集するには権限だけでなくchownコマンドでファイルの所有者を変更する必要があります。Macにrootでログインしてコマンド実行します。

[Python] 321 M1 Macへのlxml非公式インストール

[M1 Mac mini 2020 , macOS Big Sur 11.6.1]

lxmlのサイトを参考にM1 Macに非公式インストールしてみました。今のところpipコマンドではlxmlをインストールできません。miniforgeのcondaコマンドで可能です。

サイトにあったMac OS Xへのインストール方法をBig Surで試したところ、たまたま上手くいきました。

手順は以下の通りです。

1.lxml.tgzの最新版をダウンロードする。今回はver.4.6.3。

2. tgzファイルを解凍する。

3.lxml4.6.3ディレクトリをカレントディレクトリにする。

4.lxmlをsetup.pyでビルドする。ビルドが途中で終わっても先に進んで問題ありませんでした。あくまでもpandas.read_htmlの使用に限定しての話ですが。

python setup.py build --static-deps

5.lxmlをインストールする。

python setup.py install

lxml開発元はmacOSの開発環境を古いと断じており、サポートに消極的な様子が伺えました。とりあえずインストールはできたので良しとします。ビルド環境が用意されていて助かりました。

これでminiforgeに頼らずに私のpyenv環境をM1 Macにて再現できました。

[Python] 320 pandasの行名設定 index関連メソッド

データフレームの行名を設定するメソッドをまとめました。

データフレームに空白の行を挿入するコードは以下のようになります。set_index、reindex、reset_indexメソッドを駆使します。このコードによりどの分類が欠けていても処理後にAからEの全分類が明示されるようになります。

なおreindexメソッドでaxis=1にすると列名に対応します。

df2のNaNを0に置き換えないとうまくいかず、泥臭い実務的なコードになりました。この処理をしないとdf4で分類Cの行が消えてしまいます。df2からdf3は何も変わっていないように見えますが、分類Cの行に実体が入っているためreset_index処理で消えることはありません。

import pandas as pd

df = pd.read_excel('test.xlsx',sheet_name=0)
print(f"df:\n{df}\n")

df.set_index('分類',inplace=True)
print(f"dfインデックス設定後:\n{df}\n")

labels = ['A','B','C','D','E']
df2 = df.reindex(labels, axis=0)
print(f"df2:\n{df2}\n")

# 空データの分類Cを残すための処理
df3 = df2.replace({'NaN':0})
print(f"df3:\n{df3}\n")

df4 = df3.reset_index()
print(f"df4:\n{df4}\n")
--------------------------------------------------

出力
--------------------------------------------------
df:
  分類  評価額  取得額   損益
0  A  110  100   10
1  B  150  100   50
2  D  200  100  100
3  E  120  100   20

dfインデックス設定後:
    評価額  取得額   損益
分類               
A   110  100   10
B   150  100   50
D   200  100  100
E   120  100   20

df2:
      評価額    取得額     損益
分類                     
A   110.0  100.0   10.0
B   150.0  100.0   50.0
C     NaN    NaN    NaN
D   200.0  100.0  100.0
E   120.0  100.0   20.0

df3:
      評価額    取得額     損益
分類                     
A   110.0  100.0   10.0
B   150.0  100.0   50.0
C     NaN    NaN    NaN
D   200.0  100.0  100.0
E   120.0  100.0   20.0

df4:
  分類    評価額    取得額     損益
0  A  110.0  100.0   10.0
1  B  150.0  100.0   50.0
2  C    NaN    NaN    NaN
3  D  200.0  100.0  100.0
4  E  120.0  100.0   20.0