きょうこログ

初心忘れず、最後まで全力で頑張ります。よろしくお願いします。

言語処理100本ノック【第2章 前編】

課題研究で言語処理100本ノック 2015に取り組んでいます。前回の続きです。使用言語はPython3です。今回からは第2章 UNIXコマンドの基礎 です。まずは第2章前半の5つを説明します。

第2章の概要

hightemp.txtは,日本の最高気温の記録を「都道府県」「地点」「℃」「日」のタブ区切り形式で格納したファイルである.以下の処理を行うプログラムを作成し,hightemp.txtを入力ファイルとして実行せよ.さらに,同様の処理をUNIXコマンドでも実行し,プログラムの実行結果を確認せよ

10. 行数のカウント

行数をカウントせよ.確認にはwcコマンドを用いよ.

ソースコード

f = open("hightemp.txt", "r")
print(len(f.readlines()))
f.close()

open()はファイルオブジェクトを取得する関数です。第1引数には対象のファイル名、第2引数にはオブジェクトを取得する際のモードを指定します。このプログラムではファイルを読み込ん(read)で操作するので、 r モードを指定しました。実はopen()関数の第2引数はデフォルトで r を指定するので、ファイルを読み込みたい時は、モードを省略することもできます。

readlines()open()関数のメソッドで、読み込んだファイルをリストにして返します。リストの要素はファイルの各行です。例えば、

みかんは美味しい
りんごも美味しい
いちごも美味しい

というテキストファイルに対して、readlines()メソッドを用いると ["みかんは美味しい", "りんごも美味しい", "いちごも美味しい"] というリストが返ってきます。このリストの長さを数えることで行数をカウントしました。

取得した(開いた)ファイルオブジェクトは、close()メソッドで閉じ、メモリを解放します。(C言語と一緒)

UNIXコマンド

wc -l hightemp.txt

wcはファイルのバイト数、行数、文字数または単語数をカウントするコマンドです。-lをオプションに指定すると、ファイルの行数を数えることが出来ます。

実行結果

24

11. タブをスペースに置換

タブ1文字につきスペース1文字に置換せよ.確認にはsedコマンド,trコマンド,もしくはexpandコマンドを用いよ.

ソースコード

f = open("hightemp.txt", "r")
print(f.read().replace("\t", " "), end="")
f.close()

read()open()関数のメソッドで、読み込んだファイルの全てのデータを文字列型で読み込みます。replace()は文字列を置換する関数で、第1引数に指定した文字を第2引数に指定した文字に置き換えます。

read()メソッドで読み込んだデータをそのまま出力すると、print()関数の都合上末尾に 改行コードが付与されてしまいます。ここでは、endオプションを用いて末尾で改行されないようにしました。endオプションは指定した文字列を出力の末尾に付与します。(デフォルトは \n

UNIXコマンド

expand -t 1 hightemp.txt

私はUNIXコマンドにはexpandを使いました。expandはタブをスペースに変換するコマンドです。-tオプションでタブ幅( = スペースに変換すると何文字分の幅を取っているか)を指定しています。

実行結果

高知県 江川崎 41 2013-08-12
埼玉県 熊谷 40.9 2007-08-16
岐阜県 多治見 40.9 2007-08-16
(中略)
山形県 鶴岡 39.9 1978-08-03
愛知県 名古屋 39.9 1942-08-02

12. 1列目をcol1.txtに,2列目をcol2.txtに保存

ソースコード

f = open("hightemp.txt", "r")
a = open("col1.txt", "w")
b = open("col2.txt", "w")

lines = f.readlines()

for line in lines:
  datas = line.split()
  a.writelines(datas[0] + "\n")
  b.writelines(datas[1] + "\n")

f.close()
a.close()
b.close()

結果を出力するファイルである col1.txt と col2.txt は、w モードで取得します。wモードを用いると、取得したファイルオブジェクトに対して書き込み(write)を行えます。ファイルの行ごとのデータを持つ lines リストに対してfor文を実行し、得た文字列 line に対して列のデータを取得しました。列は縦向きに並んでいるデータです。

writelines()open()関数のメソッドで、ファイルオブジェクトに対して1行ずつ書き込みを行います。print()関数と違ってデフォルトで末尾に改行コードが付与されないので、改行する場合は別に \n を追記する必要があります。

UNIXコマンド

cut -f 1 hightemp.txt > col1.txt #1列目について
cut -f 2 hightemp.txt > col2.txt #2列目について

cutは文字列から所定の位置にある文字列を抜き出すコマンドです。-fオプションを用いると、指定した順番のフィールドだけを切り出す事ができます。フィールドとは特定の区切り文字列で区切られた文字列のことです。例えば、

りんご みかん いちご

という文字列に対して、"りんご"、”みかん"、”いちご” といったフィールドが順番に得られます。cutコマンドで得た出力を > を用いて別のファイルに保存しました。

実行結果

col1.txt

高知県
埼玉県
岐阜県
(中略)
山形県
愛知県

col2.txt

江川崎
熊谷
多治見
(中略)
鶴岡
名古屋

13. col1.txtとcol2.txtをマージ

12で作ったcol1.txtとcol2.txtを結合し,元のファイルの1列目と2列目をタブ区切りで並べたテキストファイルを作成せよ.確認にはpasteコマンドを用いよ.

ソースコード

a = open("col1.txt", "r")
b = open("col2.txt", "r")
f = open("col.txt", "w")

col1 = a.readlines()
col2 = b.readlines()

for data1, data2 in zip(col1, col2):
  f.writelines(data1.replace("\n", "") + "\t" + data2);

a.close()
b.close()
f.close()

col1.txt と col2.txt の結果をそれぞれ行ごとのリストで取得します。zip()は、複数のシーケンス型オブジェクトをまとめてループさせる為の関数です。このプログラムでは、2つのリストに対して先頭から同じ順番に要素を得ています。col1 から得られるデータには、不要な \n がついているので、replace()を使って除去しました。

UNIXコマンド

paste col1.txt col2.txt > col.txt

pasteは複数のファイルを行単位で連結するコマンドです。-dオプションを指定しない場合、タブ文字で連結されます。

実行結果

高知県    江川崎
埼玉県   熊谷
岐阜県   多治見
(中略)
山形県   鶴岡
愛知県   名古屋

14. 先頭からN行を出力

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

ソースコード

import sys

args = sys.argv

f = open("hightemp.txt", "r")
lines = f.readlines()

for i in range(int(args[1])):
  print(lines[i], end = "")

f.close()

コマンドライン引数をプログラムで使用するために、sysモジュールをインポートしました。sys.argvコマンドライン引数をリストで返す関数で、args[0]では実行したプログラム名が得られます。例えば、

python 13.py 3

といった風にプログラムを実行すると、args[0] = "13.py"args[1] = "3" が取得できます。このプログラムでは args[1]自然数N(ただし文字列型)が得られることが分かっているので、int()関数で int型に変換して、N個分の行を出力しました。

UNIXコマンド

head -n N hightemp.txt

headはテキストファイルの先頭のN行またはNバイトを抜き出すコマンドです。-nオプションを指定すると、指定したテキストファイルの先頭からN行を抜き出します。

実行結果

N = 3 の時

高知県    江川崎   41  2013-08-12
埼玉県   熊谷  40.9    2007-08-16
岐阜県   多治見   40.9    2007-08-16

実はこの記事は1度途中まで書いていたのですが、途中でWifiが切れてデータが吹っ飛んでしまったので、泣く泣く最初から書き直しました。こまめに保存しとくのってめっちゃ大事や…