Help us understand the problem. What is going on with this article?

Python未経験者が言語処理100本ノックをやってみる14~16

真面目に仕事をしていると投稿をサボることになり、
真面目に投稿していると仕事をサボることになる。

これは難しい問題だ・・・(真剣)
(休みの日はやらん)

これの続きでーす。
Python未経験者が言語処理100本ノックをやってみる10~13
https://qiita.com/earlgrey914/items/afdb6458a2c9f1c00c2e


14. 先頭からN行を出力

自然数Nをコマンドライン引数などの手段で受け取り,入力のうち先頭のN行だけを表示せよ.確認にはheadコマンドを用いよ.

コマンドライン引数を得るには以下のように書けばいいらしい。

arg.py
import sys
args = sys.argv

<参考URL>
https://qiita.com/orange_u/items/3f0fb6044fd5ee2c3a37

args[1]とインデックスが1から始まっているのは,実行結果を見れば理由が分かる
実行結果からわかるように,リストとして値が返される

ふむふむ。コマンドライン引数はリストとして返され、1からカウントと。

えーと、問題文が少し難解だけど、「2」がコマンドライン引数で渡されたらmerge.txtの2行を出力すればいいってことかしらね。

これでどうでしょ。

otto.py
import os.path
import sys

os.chdir((os.path.dirname(os.path.abspath(__file__))))

args = sys.argv
linedata = []

with open('merge.txt', mode="r") as f:
    linedata = f.read().splitlines()
    print(linedata[args[1])])
[ec2-user@ip-172-31-34-215 02]$ python3 enshu14.py 2
Traceback (most recent call last):
  File "enshu14.py", line 11, in <module>
    print(linedata[args[1]])
TypeError: list indices must be integers or slices, not str

おっと、コマンドライン引数argsのリストは文字列で返されるようだ。

入力値は文字列型として扱われる

では文字列→整数変換を。int(args[1])ですね

enshu14.py
import os.path
import sys

os.chdir((os.path.dirname(os.path.abspath(__file__))))

args = sys.argv
linedata = []

with open('merge.txt', mode="r") as f:
    linedata = f.read().splitlines()

for i in range(int(args[1])):
    print(linedata[i])

引数を2とか5にしてみて検証。

[ec2-user@ip-172-31-34-215 02]$ python3 enshu14.py 2
高知県  江川崎
埼玉県  熊谷
[ec2-user@ip-172-31-34-215 02]$ python3 enshu14.py 5
高知県  江川崎
埼玉県  熊谷
岐阜県  多治見
山形県  山形
山梨県  甲府
[ec2-user@ip-172-31-34-215 02]$ 

うーん簡単。
headとも比較。

[ec2-user@ip-172-31-34-215 02]$ head -n 2 merge.txt
高知県  江川崎
埼玉県  熊谷
[ec2-user@ip-172-31-34-215 02]$ head -n 5 merge.txt
高知県  江川崎
埼玉県  熊谷
岐阜県  多治見
山形県  山形
山梨県  甲府
[ec2-user@ip-172-31-34-215 02]$ 

~5日ほどサボり~

末尾のN行を出力

自然数Nをコマンドライン引数などの手段で受け取り,入力のうち末尾のN行だけを表示せよ.確認にはtailコマンドを用いよ.

リストを末尾から参照するには[-1]、[-2]、[-3]、・・・と参照していけば良いらしい。

<参考URL>
https://qiita.com/komeiy/items/971ead35d33c25923222

これ出力結果はどうなればいいんだ?
["a", "b", "c", "d"]のリストがあって、引数が2ならc, dと出力されればいいのか?d, cなのか?
tailで確認せよとのことなので、まずtailだとどう出力されるか確認してみよう。

[ec2-user@ip-172-31-34-215 02]$ tail -n 2 merge.txt
山形県  鶴岡
愛知県  名古屋
[ec2-user@ip-172-31-34-215 02]$ tail -n 5 merge.txt
埼玉県  鳩山
大阪府  豊中
山梨県  大月
山形県  鶴岡
愛知県  名古屋

なるほど。c, dの順で出せば良いんだな。

enshu15.py
import os.path
import sys

os.chdir((os.path.dirname(os.path.abspath(__file__))))

args = sys.argv
linedata = []

with open('merge.txt', mode="r") as f:
    linedata = f.read().splitlines()

linedata_reverse =[] 
for i in range(int(args[1])):
    linedata_reverse.append(linedata[-i-1])

for i in (reversed(linedata_reverse)):
    print(i)

うい。できました。
リストの反転はreversed()ですね。

[ec2-user@ip-172-31-34-215 02]$ python3 enshu15.py 2
山形県  鶴岡
愛知県  名古屋
[ec2-user@ip-172-31-34-215 02]$ python3 enshu15.py 5
埼玉県  鳩山
大阪府  豊中
山梨県  大月
山形県  鶴岡
愛知県  名古屋

結果もOK。

Pythonってこういうリストの反転とかスライスとか、便利な標準機能が多いなーって感じます。

16. ファイルをN分割する

自然数Nをコマンドライン引数などの手段で受け取り,入力のファイルを行単位でN分割せよ.同様の処理をsplitコマンドで実現せよ.

まずはsplitコマンドがどのようなものか試してみる。
お気づきかと思うが、筆者はPythonも初心者だし、UNIXコマンドも初心者である。

[ec2-user@ip-172-31-34-215 02]$ split -l 2 -d merge.txt test
[ec2-user@ip-172-31-34-215 02]$ ll
total 112
-rw-rw-r-- 1 ec2-user ec2-user 435 Mar 19 17:12 merge.txt
-rw-rw-r-- 1 ec2-user ec2-user  37 Mar 25 15:48 test00
-rw-rw-r-- 1 ec2-user ec2-user  37 Mar 25 15:48 test01
-rw-rw-r-- 1 ec2-user ec2-user  43 Mar 25 15:48 test02
-rw-rw-r-- 1 ec2-user ec2-user  34 Mar 25 15:48 test03
-rw-rw-r-- 1 ec2-user ec2-user  34 Mar 25 15:48 test04
-rw-rw-r-- 1 ec2-user ec2-user  37 Mar 25 15:48 test05
-rw-rw-r-- 1 ec2-user ec2-user  37 Mar 25 15:48 test06
-rw-rw-r-- 1 ec2-user ec2-user  37 Mar 25 15:48 test07
-rw-rw-r-- 1 ec2-user ec2-user  34 Mar 25 15:48 test08
-rw-rw-r-- 1 ec2-user ec2-user  34 Mar 25 15:48 test09
-rw-rw-r-- 1 ec2-user ec2-user  34 Mar 25 15:48 test10
-rw-rw-r-- 1 ec2-user ec2-user  37 Mar 25 15:48 test11
[ec2-user@ip-172-31-34-215 02]$ cat test00 
高知県  江川崎
埼玉県  熊谷

なるほど。
ではまず、「行単位でN分割」の部分を作ろう。

enshu16.py
import os.path
import sys

os.chdir((os.path.dirname(os.path.abspath(__file__))))

args = sys.argv
a = int(args[1])
linedata = []

with open('merge.txt', mode="r") as f:
    linedata = f.read().splitlines()

for i in range(0, len(linedata), a):
    print(linedata[i:i+a:])

とりあえずこれで、リストを分割したかのように表示することができた。

[ec2-user@ip-172-31-34-215 02]$ python3 enshu16.py 1
['高知県\t江川崎']
['埼玉県\t熊谷']
['岐阜県\t多治見']
['山形県\t山形']
['山梨県\t甲府']
['和歌山県\tかつらぎ']
['静岡県\t天竜']
['山梨県\t勝沼']
['埼玉県\t越谷']
['群馬県\t館林']
['群馬県\t上里見']
['愛知県\t愛西']
['千葉県\t牛久']
['静岡県\t佐久間']
['愛媛県\t宇和島']
['山形県\t酒田']
['岐阜県\t美濃']
['群馬県\t前橋']
['千葉県\t茂原']
['埼玉県\t鳩山']
['大阪府\t豊中']
['山梨県\t大月']
['山形県\t鶴岡']
['愛知県\t名古屋']
[ec2-user@ip-172-31-34-215 02]$ python3 enshu16.py 2
['高知県\t江川崎', '埼玉県\t熊谷']
['岐阜県\t多治見', '山形県\t山形']
['山梨県\t甲府', '和歌山県\tかつらぎ']
['静岡県\t天竜', '山梨県\t勝沼']
['埼玉県\t越谷', '群馬県\t館林']
['群馬県\t上里見', '愛知県\t愛西']
['千葉県\t牛久', '静岡県\t佐久間']
['愛媛県\t宇和島', '山形県\t酒田']
['岐阜県\t美濃', '群馬県\t前橋']
['千葉県\t茂原', '埼玉県\t鳩山']
['大阪府\t豊中', '山梨県\t大月']
['山形県\t鶴岡', '愛知県\t名古屋']
[ec2-user@ip-172-31-34-215 02]$ python3 enshu16.py 5
['高知県\t江川崎', '埼玉県\t熊谷', '岐阜県\t多治見', '山形県\t山形', '山梨県\t甲府']
['和歌山県\tかつらぎ', '静岡県\t天竜', '山梨県\t勝沼', '埼玉県\t越谷', '群馬県\t館林']
['群馬県\t上里見', '愛知県\t愛西', '千葉県\t牛久', '静岡県\t佐久間', '愛媛県\t宇和島']
['山形県\t酒田', '岐阜県\t美濃', '群馬県\t前橋', '千葉県\t茂原', '埼玉県\t鳩山']
['大阪府\t豊中', '山梨県\t大月', '山形県\t鶴岡', '愛知県\t名古屋']

次はファイルへの保存だ。
この問題では、元ファイルを 第2引数の名前+通番 の名前のファイルに分割する必要がある。
どうすればいいんだろう?

~10分ほどググる~

<参考URL>
https://news.mynavi.jp/article/zeropython-40/

なんかこういうふうに書けば連番ファイルの保存ができそう。

kou.py
for i in range(5):
    print("テスト-{0:03d}.jpg".format(i + 1))
テスト-001.jpg
テスト-002.jpg
テスト-003.jpg
テスト-004.jpg
テスト-005.jpg

format()というものを使うようだ。
個人的にものすごく難しく感じる。なんでダブルクオーテーションで囲った文字に直接.format()をつけて、値を渡せるんだ・・・?
{}の書き方のおかげだと思うんだけどこれなんて記法?

~5分ほどググる~

うーん、なんだかシックリこないなー。
別にformat()を使わずとも他の書き方でもいけるようだし、他の書き方を使おう。
よくわからんものを「動くから」と使っていると後からさらによくわからんことになる。経験則です。

<参考URL>
https://gammasoft.jp/blog/python-string-format/

書き直し↓

tes.py
for i in range(3):
    with open("テスト"+ str(i+1) +".txt", 'a') as f:
        print("てすと", file=f )
[ec2-user@ip-172-31-34-215 02]$ ll
total 124
-rw-rw-r-- 1 ec2-user ec2-user   3 Mar 27 17:15 テスト1.txt
-rw-rw-r-- 1 ec2-user ec2-user   3 Mar 27 17:15 テスト2.txt
-rw-rw-r-- 1 ec2-user ec2-user   3 Mar 27 17:15 テスト3.txt

よし、これで良い。単に連結演算子を使えばいいだけだった。
ダサいかもしれないけど、俺にとっては一番わかりやすい。

では課題の回答を作成。

enshu16.py
import os.path
import sys

os.chdir((os.path.dirname(os.path.abspath(__file__))))

args = int(sys.argv[1])
linedata = []

with open('merge.txt', mode="r") as f:
    linedata = f.read().splitlines()

for i in range(0, len(linedata), args):
    with open("テスト"+ str(i+1) +".txt", 'a') as f:
        output = linedata[i:i+args:]
        for j in output:
            print(j, file =f)
[ec2-user@ip-172-31-34-215 02]$ python3 enshu16.py 2

[ec2-user@ip-172-31-34-215 02]$ ll
total 160
-rw-rw-r-- 1 ec2-user ec2-user  37 Mar 27 17:30 テスト11.txt
-rw-rw-r-- 1 ec2-user ec2-user  37 Mar 27 17:30 テスト13.txt
-rw-rw-r-- 1 ec2-user ec2-user  37 Mar 27 17:30 テスト15.txt
-rw-rw-r-- 1 ec2-user ec2-user  34 Mar 27 17:30 テスト17.txt
-rw-rw-r-- 1 ec2-user ec2-user  34 Mar 27 17:30 テスト19.txt
-rw-rw-r-- 1 ec2-user ec2-user  37 Mar 27 17:30 テスト1.txt
-rw-rw-r-- 1 ec2-user ec2-user  34 Mar 27 17:30 テスト21.txt
-rw-rw-r-- 1 ec2-user ec2-user  37 Mar 27 17:30 テスト23.txt
-rw-rw-r-- 1 ec2-user ec2-user  37 Mar 27 17:30 テスト3.txt
-rw-rw-r-- 1 ec2-user ec2-user  43 Mar 27 17:30 テスト5.txt
-rw-rw-r-- 1 ec2-user ec2-user  34 Mar 27 17:30 テスト7.txt
-rw-rw-r-- 1 ec2-user ec2-user  34 Mar 27 17:30 テスト9.txt
-rw-rw-r-- 1 ec2-user ec2-user 530 Mar 27 17:29 enshu16.py
-rw-rw-r-- 1 ec2-user ec2-user 435 Mar 19 17:12 merge.txt

[ec2-user@ip-172-31-34-215 02]$ cat テスト1.txt 
高知県  江川崎
埼玉県  熊谷

できたぞー。
通番を0埋めしていないから並び順が無茶苦茶ね。
通番を0埋めするときは多分format()が役に立つんだろうな、と気づきました。
今回は使わないけどそのうち使います。

ここまで多分3時間くらいかかりました!!!!!!!!
2章はわりと簡単ですね。あとqiita投稿に慣れてきて、逆にやる気がなくなってきたせいでダラダラやってます。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away