質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.61%

  • Python 3.x

    5943questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

特定の文字が入ったファイルに対して中身の処理を行いたい。

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 251

tkche

score 1

 前提・実現したいこと

フォルダ内の特定の文字が入ったファイルに対して中身を処理し、処理した内容を書き込むというプログラムを作っています。1つのファイルに対しては並び変えることができ、書き込みも成功したのですが、この前pythonを始めたばかりでfor文の使い方もあっているかわからず、複数ファイルに対して実行するプログラムをなかなか書くことができず苦戦しております。

例)
test1.txt
"りんご"
"120"
"10"
"ばなな"
"140"
"2"

test2.txt
"みかん"
"160"
"40"
"ぶどう"
"300"
"3"

というようなtxtファイルがあり、みかんが入っているファイルに対して
[["みかん","160","40"],["ぶどう","300","3"]]のように3行ごとにリストのリストに加え、各リストの3つ目の数字が小さい順に並び変えたものを作り、次のように書きこみたい。
narabikae.txt
"ぶどう"
"みかん"

1つのファイルに対して行ったプログラムは次の通りです。

f = open('test.txt',encoding="utf-8-sig")
data1 = f.read()  
f.close()

lines1 = data1.split('\n') 
print(lines1) 

i = 0
list1 = []
list2 = []

i = 0

for line in lines1:

    if i%3 == 0:
        list1.append(lines1[i]) 
    if i%3 == 1:
        list1.append(int(lines1[i]))        
    if i%3 == 2:
        list1.append(int(lines1[i])) 
        list2.append(list1)

        list1 = []
    i += 1
    print(line)
print(list2)

from operator import itemgetter

list2.sort(key=itemgetter(2))
print(format(list2))

f = open('narabikae.txt','w')

j = 0

for j in range(len(list2)):

    f.write(list2[j][0])
    f.write('\n')


f.close()

 発生している問題・エラーメッセージ

 該当のソースコード

ソースコード

 試したこと

 補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • tkche

    2018/04/15 19:09

    お返事ありがとうございます。例ではみかんは1行目に来ておりますが、内容が何十行にもなるファイルの処理も考えていますのでその場合もございます。

    キャンセル

  • LouiS0616

    2018/04/15 19:11

    『みかん』がtext2.txt、text3.txtにあった場合、それぞれnarabikae2.txt、narabikae3.txtを作るのでしょうか。

    キャンセル

  • tkche

    2018/04/15 19:14

    お返事ありがとうございます。はい、そのようなものを考えております。

    キャンセル

回答 2

checkベストアンサー

+2

とりあえず、一つのファイルに対する処理を関数化します。記述を簡略化しましたが、処理内容はみかんが含まれていないファイルなら処理を中断するようにした以外は変えていません(私のミスがなければ)。まあ、これは参考にしてください。

def mikan(input_filename, output_filename):
    f = open(input_filename, encoding="utf-8-sig")
    data1 = f.read()  
    f.close()

    if "みかん" not in data1:
        return 

    lines1 = data1.split('\n') 
    print(lines1) 

    result = []
    for i, line in enumerate(lines1):
        if i%3 == 0:
            tmp = []
            tmp.append(line) 
        if i%3 == 1:
            tmp.append(int(line))        
        if i%3 == 2:
            tmp.append(int(line)) 
            result.append(tmp)

    result.sort(key=lambda x:x[2])

    f = open(output_filename,'w')
    for data in result:
        f.write(data[0])
        f.write('\n')
    f.close()

次に複数ファイルの取得方法ですが、os.listdirを使うとあるディレクトリ以下のファイル一覧が取れるので、さしあたってはこれを使えば良いでしょう。特定のディレクトリ(pythonファイルを置いたディレクトリに作ると簡単です)にデータをすべて放り込んでおきます。そのディレクトリとは別に、出力を保存するディレクトリも作っておきます。あとは下のような雰囲気でやれば良いでしょう(ファイル名などは適当です)。

import os
data_dir = # 適切なデータディレクトリ名文字列("dirname/")
output_dir = # 適切な出力ディレクトリ名文字列("dirname/")

for data_filename in os.listdir(data_dir):
    mikan(data_dir + data_filename, output_dir + data_filename + ".narabikae.txt")

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/15 20:47

    回答ありがとうございます、実行してみたところ
    UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 1: invalid start byte
    とエラーが出たのですがファイルの読み込みの際にどのようなコードを加えればよいでしょうか。

    キャンセル

  • 2018/04/15 20:54

    エラーが出ている行はどこですか?

    キャンセル

  • 2018/04/15 21:12

    該当箇所があっているか怪しいですが
    File "C:\Users\2017math1\Anaconda3\lib\encodings\utf_8_sig.py", line 69, in _buffer_decode
    return codecs.utf_8_decode(input, errors, final)
    というふうに出ています。

    キャンセル

  • 2018/04/15 21:20

    tracebackが出てると思うので、ぜんぶ貼ってください(ディレクトリ名などで個人情報が含まれていれば適宜伏せてくれて構いません)。それと、オリジナルのプログラムが実行できることをもう一度確認してください。

    キャンセル

  • 2018/04/15 21:30

    オリジナルのほうを実行してみましたがそちらは実行できました。

    File "<ipython-input-563-6ec6aa36de3a>", line 1, in <module>
    runfile('C:/Users/2017math1/Desktop/narabikae/narabikae1.py', wdir='C:/Users/2017math1/Desktop/narabikae')

    File "C:\Users\2017math1\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 880, in runfile
    execfile(filename, namespace)

    File "C:\Users\2017math1\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 102, in execfile
    exec(compile(f.read(), filename, 'exec'), namespace)

    File "C:/Users/2017math1/Desktop/narabikae/narabikae1.py", line 13, in <module>
    narabi(data_dir + data_filename, output_dir + data_filename + ".narabikae.txt")

    File "C:/Users/2017math1/Desktop/narabikae/koredeowarida2.py", line 10, in narabi
    output_dir = "C:/Users/2017math1/Desktop/narabikaego/"

    File "C:\Users\2017math1\Anaconda3\lib\codecs.py", line 321, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)

    File "C:\Users\2017math1\Anaconda3\lib\encodings\utf_8_sig.py", line 69, in _buffer_decode
    return codecs.utf_8_decode(input, errors, final)

    UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 1: invalid start byte

    になります。何度もすみません。

    キャンセル

  • 2018/04/15 21:50

    何回も確認させて申し訳ないのですが、使っているpythonのバージョンを確認してください。わからなければimport sys;print(sys.version)をコードの先頭に書いて確認できます。python3.xタグが付いていたのでpython3系を想定してプログラムを書きましたが、2系だとちょっと面倒なことになります。
    次に、スクリプトファイルの文字コードを確認してください。基本的にはutf-8にしておくのが望ましいです。

    キャンセル

  • 2018/04/15 22:22

    Anacondaのspyderというものを使っておりまして、python3.6と書かれているので3系ではあると思われます。文字コードはすべてutf-8で保存してあります。
    一つのファイルに対して実行するほうはエラー無く動いたのですが、lines1になにも入っていないようでprintできない状態です。txtファイルがおかしいのでしょうか・・・

    キャンセル

  • 2018/04/15 22:35

    >printできない状態
    これについて詳しく教えてください。正常にprintされないのですか?

    キャンセル

  • 2018/04/15 22:54

    そのようです、エラーはないのですがprintされてません。回答していただいたコードの中で私が変更しなければいけない箇所はどこでしょうか。質問ばかりですみません。

    キャンセル

  • 2018/04/15 22:57

    確認ですが、「printされない」のは質問者様が質問文に貼ったコードですか? それとも私のコードを一つのファイルに対して実行した場合ですか?
    また、まったくprint結果が出ないという状況でよろしいですか?

    キャンセル

  • 2018/04/15 23:03

    printされないのは回答していただいたコードです。

    キャンセル

  • 2018/04/15 23:08

    すみません、私のコードは入力データにみかんが含まれていないとprintされません・・・
    最初の f.close()のあとにprint(data1)を追加してください。
    lines1 = data1.split('\n')
    print(lines1)
    も同じ位置に移動してしまって良いです。これでたぶん表示されるようになると思います。

    キャンセル

  • 2018/04/15 23:24

    私が間違ってるかもしれないのですが、回答していただいたinput_filename や output_filenameを一番最初に input_filename = "text3.txt" output_filename = "narabikaego.txt"としたのですがこれはいいのでしょうか?
    これが原因でprintされないのかもしれないです。

    キャンセル

  • 2018/04/15 23:30

    関数の形で作りましたから、それらは引数に渡して呼び出してあげてください。
    回答には示していませんが、次のように呼び出すことを想定しています。
    mikan("text3.txt", "narabikaego.txt")
    これはdefブロックの外に書いてください。

    キャンセル

  • 2018/04/15 23:44

    やはりprint結果が表示されないようです、、、
    私に原因があるんでしょうけど、どこが悪いのかがわかりません。

    キャンセル

  • 2018/04/15 23:45

    とりあえずその分のコードは質問文に載せてみてください。私もそろそろ現状がよくわからなくなってきたので・・・

    キャンセル

  • 2018/04/16 00:04

    input_filename = "text3.txt"
    output_filename = "narabikaego.txt"

    def mikan(input_filename, output_filename):
    f = open(input_filename, encoding="utf-8")
    data1 = f.read()
    f.close()
    print(data1)
    lines1 = data1.split('\n')
    print(lines1)

    if "みかん" not in data1:
    return

    result = []
    for i, line in enumerate(lines1):
    if i%3 == 0:
    tmp = []
    tmp.append(line)
    if i%3 == 1:
    tmp.append(int(line))
    if i%3 == 2:
    tmp.append(int(line))
    result.append(tmp)

    result.sort(key=lambda x:x[2])

    f = open(output_filename,'w')
    for data in result:
    f.write(data[0])
    f.write('\n')
    f.close()

    text3.txt
    "ぶどう"
    1351699628
    932
    "みかん"
    1351699719
    1568
    "イイネ"
    1351699735
    1276
    "パイナップル"
    1351700208
    1696
    "おいしい"
    1351699318
    808

    です。

    キャンセル

  • 2018/04/16 00:09

    ソースコードの一番下の行に、インデントなしで
    mikan(input_filename , output_filename)
    を書いてください。とりあえず、これでこっちは動くはずです。

    キャンセル

  • 2018/04/16 00:31

    ありがとうございます、こちらは無事動いてくれました;;

    キャンセル

  • 2018/04/16 15:17

    了解しました。文字コードの方は相変わらずよくわからないので、とりあえず処理を細かく分けてどこで落ちてるのかはっきりさせてみましょう。恐らく関数を呼び出す前だと思うので、文字列連結を関数呼び出しの外に持っていってみます。ついでに型を調べて変なことになっていないか確認します。
    インデントを_で代用しています

    import os
    data_dir = # 適切なデータディレクトリ名文字列("dirname/")
    output_dir = # 適切な出力ディレクトリ名文字列("dirname/")
    print(type(data_dir), type(output_dir))

    for data_filename in os.listdir(data_dir):
    ____input_filename = data_dir + data_filename
    ____output_filename = output_dir + data_filename + ".narabikae.txt"
    ____print(type(input_filename), type(output_filename))
    ____mikan(input_filename, output_filename)

    キャンセル

  • 2018/04/16 20:01

    ありがとうございます。実行しましたところ、型はすべてstrのようです。

    キャンセル

  • 2018/04/16 20:40

    この処理はどの段階でエラーを吐いて落ちますか?

    キャンセル

  • 2018/04/16 20:54

    上のmikan(input_filename,output_filename)をインデントありで実行すると38行目に
    ValueError: invalid literal for int() with base 10: '"""'
    とエラーが出るようです。
    インデントなしで実行すると出力ファイルに1つだけ書かれていました。

    キャンセル

  • 2018/04/16 21:20

    では、 for i, line in enumerate(lines1):の行の直下にインデントして次の記述を入れてください。
    print(i, line)
    これでどこでエラーが出るか見てみよう、という作戦です。

    キャンセル

  • 2018/04/16 21:21 編集

    憶測ですがファイルの最後に複数入っている改行が空文字列を作ってしまった結果な気がするので、上に書いたprintをした結果それが裏付けられたのなら、
    lines1 = data1.split('\n')
    の行を
    lines1 = [x for x in data1.split('\n') if x != ""]
    と書き換えてください。リストから空文字列を除去するコードです。

    キャンセル

  • 2018/04/16 21:42

    回答者様のおっしゃる通り、最後の行に改行が含まれていました。
    lines1を上記のように書き換えたのですが同じエラーが表示されました。

    キャンセル

  • 2018/04/16 21:45

    エラーが出るまでに入れたprintが何回か出力を出してると思うので、その結果をとりあえず貼ってみてください

    キャンセル

  • 2018/04/16 21:53

    すごくごちゃごちゃしているのですが
    <class 'str'> <class 'str'>
    <class 'str'> <class 'str'>
    ['# -*- coding: utf-8 -*-', '"""', 'Created on Mon Apr 16 21:52:07 2018', '@author: 2017math1', '"""', 'import os', 'data_dir = "C:/Users/2017math1/Desktop/narabimae/"', 'output_dir = "C:/Users/2017math1/Desktop/narabikaego/"', 'print(type(data_dir), type(output_dir))', 'for data_filename in os.listdir(data_dir):', ' input_filename = data_dir + data_filename', ' output_filename = output_dir + data_filename + ".narabikae.txt"', ' print(type(input_filename), type(output_filename))', ' mikan(input_filename, output_filename)', 'def mikan(input_filename, output_filename):', ' f = open(input_filename, encoding="utf-8-sig")', ' data1 = f.read() ', ' f.close()', ' if "みかん" not in data1:', ' return ', ' lines1 = [x for x in data1.split(\'\\n\') if x != ""]', ' print(lines1) ', ' result = []', ' for i, line in enumerate(lines1):', ' print(i,line)', ' if i%3 == 0:', ' tmp = []', ' tmp.append(line) ', ' if i%3 == 1:', ' tmp.append(int(line)) ', ' if i%3 == 2:', ' tmp.append(int(line)) ', ' result.append(tmp)', ' result.sort(key=lambda x:x[2])', " f = open(output_filename,'w')", ' for data in result:', ' f.write(data[0])', " f.write('\\n')", ' f.close()']
    0 # -*- coding: utf-8 -*-
    1 """

    です

    キャンセル

  • 2018/04/16 22:04

    どうもソースコード(**.py)を入力として渡してしまっている気がします。ひょっとして対象データと**.pyが同階層にある?
    とりあえず、以下のディレクトリ構造に直してみてくださいな
    ..(省略)/Desktop/narabikae/
    ┣narabikae.py(実行するスクリプト、名前は任意)
    ┣narabimae/(処理対象のデータ「のみ」入ったフォルダ)
    ┗narabikaego/
    data_dir, output_dirは適切に変更しておいてください(.../Desktop/narabikae/narabimae/, ../Desktop/narabikae/narabikaego/とでもすれば良いです)

    キャンセル

  • 2018/04/16 22:20

    無事動いてくれました! 本当に何から何までありがとうございますm(__)m
    お聞きしたいことがあるのですが、pythonやほかの言語はどのように習得されたのでしょうか?
    最後までばかりですみません。

    キャンセル

  • 2018/04/16 22:46

    動くまでに一日以上かかっちゃいましたね。さくっと解決できなくて、こちらも申し訳なかったです。回答者として色々反省点があったので(ディレクトリの話とかしっかり説明しておくべきでした)、今後の教訓にさせていただきます
    プログラミングの習得の件は、私が答えると「学校の課題や研究で必要に迫られて覚えました」という面白みのない、参考にもならない話にしかなりません。別に質問立てて、色々な人から聞いてみたらどうです? 書き方が悪いと「問題・課題が含まれていない質問」とか低評価飛ばされちゃうかもしれないけど

    キャンセル

  • 2018/04/16 22:58

    すみません、指摘がとても的確でどのように習得したのか興味があったものですから。
    いろいろなところでまた聞いてみたいと思います。
    今回は本当にありがとうございましたm(__)m

    キャンセル

+1

pathlibを使うとこんな感じです。

from operator import itemgetter
from pathlib import Path

def analyze_file(fin):
    lines = fin.readlines()

    if '"みかん"\n' not in lines[0::3]:
        return []

    data = [
        [f, int(key.strip('"\n'))] 
        for f, _, key in zip(*[iter(lines)]*3)
    ]
    return [elem[0] for elem in sorted(data, key=itemgetter(-1))]


parent_dir = Path(r'textがあるディレクトリ')
for filename in parent_dir.glob('text*.txt'):
    i = int(filename.name[4])  # 二桁以上の場合もあるならもうちょっと工夫が必要

    fin_path  = (parent_dir / f'text{i}.txt')
    fout_path = (parent_dir / f'narabikae{i}.txt')

    with fin_path.open() as fin:
        result = analyze_file(fin)

    if not result:
        continue

    with fout_path.open(mode='w') as fout:
        fout.writelines(result)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Python 3.x

    5943questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。