パスワードを忘れた? アカウント作成
13440717 journal
日記

tuneoの日記: 他人の書いたuglyなPythonコードを読まされるという苦行

日記 by tuneo

架空のコマンドaboutを実行すると、こんな具合に標準出力にメッセージが吐かれると思いねぇ。(カッコ内は注釈)

$ about tuneo
Name: tuneo
        homepage = https://srad.jp/~tuneo/
        profile = I was born in Kanagawa pref. (←ピリオドの後に空白を入れて改行している)
                I can read and write Python code, but I'm not good at mathematics.(←ピリオドの後に空白を入れて改行している)
                I have some PCs in my room(2 tablet PCs, 2 notebook PCs, 3 desktop PCs)
        my_own_fastest_cpu = Intel Core i7-2600

で、これをPythonスクリプトに食わせて

about_result = {
  "Name" : "tuneo",
  "homepage" : "https://srad.jp/~tuneo/",
  "profile" : "I was born in Kanagawa pref. I can read and write Python code, but I'm not good at mathematics. I have some PCs in my room(2 tablet PCs, 2 notebook PCs, 3 desktop PCs)"
  "my_own_fastest_cpu" : "Intel Core i7-2600"
}

という辞書を作りたいと思っていただきたい。つまりaboutの出力書式をまとめるとこういうことだ。

  • 最初の1行はインデントレベル0で、しかも"キー: 値"というフォーマット
  • 次の行から1レベルインデントされて"キー = 値"というフォーマット
  • もう1レベル深くインデントされている行は前の行からの継続なので連結する

これを実現するための他人が書いたコードを読まされたんだが……苦痛の一言だった。アルゴリズムがクソすぎるのだ。疑似コードはこんな感じだ。うろ覚えの「感じ」なので動かんかもしれないけど(苦笑

result = {}
p = subprocess.Popen("about tuneo", stdout = subprocess.PIPE)
 
for line in p.stdin:
  prev_line = ""
  level = get_indent_level(line)
  if level = 0: # 一行目の"<name>: <value>"
    prev_line = line
    continue
  elif level == 4: # 2行目以降
    line = line.lstrip()
    if ": " in prev_line: # prev_lineに1行目が入ってる
       key, value = ": ".split(prev_line)
       result[key] = value
       prev_line = ""
    elif prev_line: # 前の行まで行連結してました
       key, value = " = ".split(prev_line)
      result[key] = value
    key, value = " = ".split(line)
    result[key] = value
    prev_line = line
  elif level == 8: # 行連結の途中
    prev_line += line.lstrip()
    continue

「醜悪」の一言に尽きるわな。実際、入力データ(aboutコマンドの出力)を見ながらコードを脳内ステップ実行しないと何をしてるのかさっぱりわからんかった。

手始め。ここには出てこないインデントレベルを調べるget_indent_level()だが、恐ろしいことにforループをぶん回して「行をスキャンして行頭の空白文字を数える」処理を一生懸命やっているのだ。正規表現モジュールreを使えばいいじゃんよ……。
# 余談だが、別のスクリプトでは固定文字列の置換にreモジュールを使っていたな。

そして最初の行のName: tuneoの処理だけど、なんでこれをその場でやらんで「前の行のバッファ」とかいうふざけたものに格納だけしてcontinueしているのか意味が分からん。その場でsplit()してresultに格納しろよ。

そして2行目以降の入力を処理する意味不明なロジック。挙動を理解した瞬間「俺ならもっとうまくやる」とかまるで「ベルセルク」のガッツみたいな台詞を吐いてしまったことであったよ。1行読むたびに1行目かどうか判定するとか愚の骨頂だろ。

この議論は、tuneo (2938)によって テキとトモのテキ禁止として作成されたが、今となっては 新たにコメントを付けることはできません。
typodupeerror

Stay hungry, Stay foolish. -- Steven Paul Jobs

読み込み中...