素人の言語処理100本ノック:16

  • 0
    いいね
  • 2
    コメント

    言語処理100本ノック 2015の挑戦記録です。環境はUbuntu 16.04 LTS + Python 3.5.2 :: Anaconda 4.1.1 (64-bit)です。過去のノックの一覧はこちらからどうぞ。

    第2章: UNIXコマンドの基礎

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

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

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

    出来上がったコード:

    main.py
    # coding: utf-8
    import math
    
    fname = 'hightemp.txt'
    n = int(input('N--> '))
    
    with open(fname) as data_file:
        lines = data_file.readlines()
    
    count = len(lines)
    unit = math.ceil(count / n)  # 1ファイル当たりの行数
    
    for i, offset in enumerate(range(0, count, unit), 1):
        with open('child_{:02d}.txt'.format(i), mode='w') as out_file:
            for line in lines[offset:offset + unit]:
                out_file.write(line)
    

    実行結果:

    一例として、N=5の場合の結果を載せます。
    全部で24行なので、5分割すると各ファイルは5行になり、最後のファイルだけは4行になります。

    child_01.txt
    高知県   江川崎   41  2013-08-12
    埼玉県   熊谷  40.9    2007-08-16
    岐阜県   多治見   40.9    2007-08-16
    山形県   山形  40.8    1933-07-25
    山梨県   甲府  40.7    2013-08-10
    
    child_02.txt
    和歌山県    かつらぎ    40.6    1994-08-08
    静岡県   天竜  40.6    1994-08-04
    山梨県   勝沼  40.5    2013-08-10
    埼玉県   越谷  40.4    2007-08-16
    群馬県   館林  40.3    2007-08-16
    
    child_03.txt
    群馬県   上里見   40.3    1998-07-04
    愛知県   愛西  40.3    1994-08-05
    千葉県   牛久  40.2    2004-07-20
    静岡県   佐久間   40.2    2001-07-24
    愛媛県   宇和島   40.2    1927-07-22
    
    child_04.txt
    山形県   酒田  40.1    1978-08-03
    岐阜県   美濃  40  2007-08-16
    群馬県   前橋  40  2001-07-24
    千葉県   茂原  39.9    2013-08-11
    埼玉県   鳩山  39.9    1997-07-05
    
    child_05.txt
    大阪府   豊中  39.9    1994-08-08
    山梨県   大月  39.9    1990-07-19
    山形県   鶴岡  39.9    1978-08-03
    愛知県   名古屋   39.9    1942-08-02
    

    UNIXコマンド確認用のシェルスクリプト:

    test.sh
    #!/bin/sh
    
    # Nを入力
    echo -n "N--> "
    read n
    
    # 行数算出 wcは行数とファイル名を出力するのでcutで行数のみ切り出し
    count=`wc --line hightemp.txt | cut --fields=1 --delimiter=" "`
    
    # 1分割当たりの行数算出 余りがある場合は行数を+1
    unit=`expr $count / $n`
    remainder=`expr $count % $n`
    if [ $remainder -gt 0 ]; then
        unit=`expr $unit + 1`
    fi
    
    # 分割
    split --lines=$unit --numeric-suffixes=1 --additional-suffix=.txt hightemp.txt child_test_
    
    # 検証
    for i in `seq 1 $n`
    do
        fname=`printf child_%02d.txt $i`
        fname_test=`printf child_test_%02d.txt $i`
        diff --report-identical-files $fname $fname_test
    done
    

    結果の確認:

    いくつかの結果を載せます。

    N=1の場合:

    端末
    segavvy@ubuntu:~/ドキュメント/言語処理100本ノック2015/16$ python main.py 
    N--> 1
    segavvy@ubuntu:~/ドキュメント/言語処理100本ノック2015/16$ ./test.sh
    N--> 1
    ファイル child_01.txt と child_test_01.txt は同一です
    

    N=2の場合:

    端末
    segavvy@ubuntu:~/ドキュメント/言語処理100本ノック2015/16$ python main.py 
    N--> 2
    segavvy@ubuntu:~/ドキュメント/言語処理100本ノック2015/16$ ./test.sh
    N--> 2
    ファイル child_01.txt と child_test_01.txt は同一です
    ファイル child_02.txt と child_test_02.txt は同一です
    

    N=5の場合:

    端末
    segavvy@ubuntu:~/ドキュメント/言語処理100本ノック2015/16$ python main.py 
    N--> 5
    segavvy@ubuntu:~/ドキュメント/言語処理100本ノック2015/16$ ./test.sh
    N--> 5
    ファイル child_01.txt と child_test_01.txt は同一です
    ファイル child_02.txt と child_test_02.txt は同一です
    ファイル child_03.txt と child_test_03.txt は同一です
    ファイル child_04.txt と child_test_04.txt は同一です
    ファイル child_05.txt と child_test_05.txt は同一です
    

    N=7の場合:

    端末
    segavvy@ubuntu:~/ドキュメント/言語処理100本ノック2015/16$ python main.py 
    N--> 7
    segavvy@ubuntu:~/ドキュメント/言語処理100本ノック2015/16$ ./test.sh
    N--> 7
    ファイル child_01.txt と child_test_01.txt は同一です
    ファイル child_02.txt と child_test_02.txt は同一です
    ファイル child_03.txt と child_test_03.txt は同一です
    ファイル child_04.txt と child_test_04.txt は同一です
    ファイル child_05.txt と child_test_05.txt は同一です
    ファイル child_06.txt と child_test_06.txt は同一です
    diff: child_07.txt: そのようなファイルやディレクトリはありません
    diff: child_test_07.txt: そのようなファイルやディレクトリはありません
    

    今回のプログラムでは6分割しかされないので、7分割目のファイルがない旨のエラーになります。これは、全24行を7分割しようとすると1ファイル当たり4行になってしまい、6ファイルで済んでしまうロジックのためです。
    もしかしたら、4行のファイルを3つと、3行のファイルを4つに分割しないといけないかも知れません。このコードだと不正解かも...^^;

    N=24の場合:

    端末
    segavvy@ubuntu:~/ドキュメント/言語処理100本ノック2015/16$ python main.py
    N--> 24
    segavvy@ubuntu:~/ドキュメント/言語処理100本ノック2015/16$ ./test.sh
    N--> 24
    ファイル child_01.txt と child_test_01.txt は同一です
    ファイル child_02.txt と child_test_02.txt は同一です
    ファイル child_03.txt と child_test_03.txt は同一です
    ファイル child_04.txt と child_test_04.txt は同一です
    ファイル child_05.txt と child_test_05.txt は同一です
    ファイル child_06.txt と child_test_06.txt は同一です
    ファイル child_07.txt と child_test_07.txt は同一です
    ファイル child_08.txt と child_test_08.txt は同一です
    ファイル child_09.txt と child_test_09.txt は同一です
    ファイル child_10.txt と child_test_10.txt は同一です
    ファイル child_11.txt と child_test_11.txt は同一です
    ファイル child_12.txt と child_test_12.txt は同一です
    ファイル child_13.txt と child_test_13.txt は同一です
    ファイル child_14.txt と child_test_14.txt は同一です
    ファイル child_15.txt と child_test_15.txt は同一です
    ファイル child_16.txt と child_test_16.txt は同一です
    ファイル child_17.txt と child_test_17.txt は同一です
    ファイル child_18.txt と child_test_18.txt は同一です
    ファイル child_19.txt と child_test_19.txt は同一です
    ファイル child_20.txt と child_test_20.txt は同一です
    ファイル child_21.txt と child_test_21.txt は同一です
    ファイル child_22.txt と child_test_22.txt は同一です
    ファイル child_23.txt と child_test_23.txt は同一です
    ファイル child_24.txt と child_test_24.txt は同一です
    

    N=25の場合:

    端末
    segavvy@ubuntu:~/ドキュメント/言語処理100本ノック2015/16$ python main.py
    N--> 25
    segavvy@ubuntu:~/ドキュメント/言語処理100本ノック2015/16$ ./test.sh
    N--> 25
    ファイル child_01.txt と child_test_01.txt は同一です
    ファイル child_02.txt と child_test_02.txt は同一です
    ファイル child_03.txt と child_test_03.txt は同一です
    ファイル child_04.txt と child_test_04.txt は同一です
    ファイル child_05.txt と child_test_05.txt は同一です
    ファイル child_06.txt と child_test_06.txt は同一です
    ファイル child_07.txt と child_test_07.txt は同一です
    ファイル child_08.txt と child_test_08.txt は同一です
    ファイル child_09.txt と child_test_09.txt は同一です
    ファイル child_10.txt と child_test_10.txt は同一です
    ファイル child_11.txt と child_test_11.txt は同一です
    ファイル child_12.txt と child_test_12.txt は同一です
    ファイル child_13.txt と child_test_13.txt は同一です
    ファイル child_14.txt と child_test_14.txt は同一です
    ファイル child_15.txt と child_test_15.txt は同一です
    ファイル child_16.txt と child_test_16.txt は同一です
    ファイル child_17.txt と child_test_17.txt は同一です
    ファイル child_18.txt と child_test_18.txt は同一です
    ファイル child_19.txt と child_test_19.txt は同一です
    ファイル child_20.txt と child_test_20.txt は同一です
    ファイル child_21.txt と child_test_21.txt は同一です
    ファイル child_22.txt と child_test_22.txt は同一です
    ファイル child_23.txt と child_test_23.txt は同一です
    ファイル child_24.txt と child_test_24.txt は同一です
    diff: child_25.txt: そのようなファイルやディレクトリはありません
    diff: child_test_25.txt: そのようなファイルやディレクトリはありません
    

    全部で24行しかないので、25分割はできません。このエラーは仕方ないかと思います。

    今回はpythonよりもシェルスクリプトに苦労しましたが、少し慣れてきました。printfというコマンドまであることを知って、UNIXコマンドの多彩さに驚いています。
     
    17本目のノックは以上です(いつも最後に書いているノックの本数が1本ずれていませんか?とのご指摘をいただきましたが、このノックの最初の問題番号は0なので、問題番号とは1本ずれています)。誤りなどありましたら、ご指摘いただけますと幸いです。