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

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

ただいまの
回答率

90.50%

  • Python

    8002questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

python 文字 照合

解決済

回答 2

投稿 編集

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

aaa12

score 10

こんにちは。pythonでの数字列の照合方法についてお伺いしたく、質問させていただきます。

まず、こちらは以前教えていただいたコードです。

hoge_dict = {}

for line in f1:
   hoge_dict[line.split(';')[0]] = line.rstrip()

for line in f2:
    line = line.rstrip()
    if line in hoge_dict:
            f3.write(str(hoge_dict[line]) + '\n')
            print(hoge_dict[line])

LouiS0616さんありがとうございます。
これは、f1に以下のような数字が入っており、
123456;7898553
145454;4538573
123456;4598295
:
:

f2に以下のような数字が入っています
134315
123456
:
そしてf1の;より左側と、f2の数字が一致したらf1の内容を出力し、f3
に書き込むというコードでした。

①今度はこれをf1の両側がf2に含まれている場合のみ、f1の内容を出力というものにしたいです。そのコードについて、自分で書いてみたのですが、見当違いだと思うので教えていただきたいです。

②f1の内容が
123457465786    134354365436   435435  341535  12344  1123456  343534   
:
のように7つのデータになり、かつタブ区切りになった場合6番目の数字とf2が一致した場合新しいファイルに書き込む方法を教えていただきたいです。(f2のファイルには途中空行が混ざっている場合があるのでtry分で処理しています)
こちらは自分で以下のようなコードを書きましたが、エラーは出ずに実行されるのですがファイルに書き込まれていませんし、print分の内容も表示されません。わかる方、教えていただきたいです。

hoge_dict = {}

try:
    for line in f1:
        hoge_dict[line.split('\t')[5]] = line.rstrip()

except:
    pass

else:
    for line in f2:
        line = line.rstrip()
        if line in hoge_dict:
            f3.write(str(hoge_dict[line]) + '\n')
            print(hoge_dict[line])

たぶ区切りの5番目と照合、これではなぜ駄目なのでしょうか?
理由もわからないです。
よろしくお願いします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • Lhankor_Mhy

    2017/10/28 14:11

    try except 文を使えばいいと思います。https://docs.python.jp/3/tutorial/errors.html#handling-exceptions

    キャンセル

  • aaa12

    2017/10/28 14:15

    ありがとうございます!

    キャンセル

  • aaa12

    2017/11/08 10:15

    こんにちは、以前質問したものです。わからない箇所が出てきたのですが、もう一度お伺いしてよろしいですか?

    キャンセル

回答 2

checkベストアンサー

+1

①今度はこれをf1の両側がf2に含まれている場合のみ、f1の内容を出力というものにしたいです。そのコードについて、自分で書いてみたのですが、見当違いだと思うので教えていただきたいです。

オリジナルのコードが見つかりませんが、
f1の両側がf2に含まれている場合、というのであれば、

hoge_set = set([])

for line in f2:
    key = line.rstrip()
    hoge_set.add(key)

for line in f1:
    line = line.rstrip()
    items = line.split(';')
    if items[0] in hoge_set and items[1] in hoge_set:
            f3.write(line + '\n')
            print(line)

②f1の内容が
123457465786    134354365436   435435  341535  12344  1123456  343534   
:
のように7つのデータになり、かつタブ区切りになった場合6番目の数字とf2が一致した場合新しいファイルに書き込む方法を教えていただきたいです。(f2のファイルには途中空行が混ざっている場合があるのでtry分で処理しています)
こちらは自分で以下のようなコードを書きましたが、エラーは出ずに実行されるのですがファイルに書き込まれていませんし、print分の内容も表示されません。わかる方、教えていただきたいです。

print文が実行されていないところを見るとtry-exceptにキャッチされたと考えるべきでしょう。

try:
    ...
except Exception as e:
    print(e)
else:
    ....


として、どんなエラーが出されたのかをデバッグすると良いと思います。
おそらく、f1の空行か.split('\t')が原因で[5]で配列外をアクセスしたせいだと想像しますが。
手元ではデータ等がないので再現できませんが、タブであれば、.split()だけでも区切りを処理できると思われます。
ところで、f2に空行があってもなくてももとのコードでは問題とはなりません。
一方で、もとのコードだとf1に空行があるとうまく動きません。
理由はf1に空行がある場合はtry文の場所が正しくないからです。

hoge_dict = {}

for line in f1:
    try:
        hoge_dict[line.split()[5]] = line.rstrip()
    except Exception as e:
        print(e, 'blank line skipping')

for line in f2:
    line = line.rstrip()
    if line in hoge_dict:
        f3.write(str(hoge_dict[line]) + '\n')
        print(hoge_dict[line])

ちなみにこのhoge_dictを使った方法、keyとなる部分が一意的ではないとvalueは最後に出現したものに更新されていきます。
ゆえに、f1の6番目がf2に含まれているすべてのラインが求められている場合、出力が正しくありません。
このままだと、f1の6番目がf2に含まれているラインのうち最後のものが出力されます。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/11/08 15:48

    お返事ありがとうございます。
    とても丁寧な文章で、①については理解することができました!
    ②の実行をしたところこのようなエラーが出ました。(IndexError('list index out of range',), 'blank line skipping')

    私の理解不足でこのコードの実行できない理由がまだわかっていないのですが、f1に空白があるため実行できないということでしょうか?

    キャンセル

  • 2017/11/08 15:57

    f1に空白文があるとline.split()の返り値が[]となるはずです。(print(line.split())をしてみればわかります。)
    このリストには中身がありませんので、6番目の要素は存在せず、line.split()[5]はリストの外側をアクセスしようとしてIndexErrorを出します。
    そして、それをexcept文で受け取って念のために空行があることを出力しているだけで、コード自体は問題なく実行されているはずです。

    最後にprint('Done')と追記すれば、実行終了後にDoneと表示されて、実際に最後まで実行しきったと安心できます。

    キャンセル

  • 2017/11/08 16:00

    丁寧にありがとうございます!おっしゃている意味がわかりました。tryでf1に空行ができてもそれを知らせるだけでそこは飛ばして実行するということですよね?ありがとうございます。
    このエラーは無視して実行が終わるのを待てば良いという解釈であっていますか?

    キャンセル

  • 2017/11/08 16:04

    それで正しいです。

    もとのコードでも同様のエラーを出していますが、printして出力しているのではなく、passで潰しているだけです。
    エラーと出力されて気持ち悪いのであれば、print文をpassで置き換えると出力はスッキリします。

    キャンセル

  • 2017/11/08 16:06

    ありがとうございます!それで実行してみます。データが莫大なため実行に時間がかかってしまいますが、正しくできたらまたお伝えいたします。ありがとうございます。

    キャンセル

  • 2017/11/08 16:57

    無事に実行できました、ありがとうございます!

    キャンセル

  • 2017/11/08 18:05

    うまくいってよかったです。

    キャンセル

  • 2017/11/08 21:39

    度々申し訳ありません。実行は出来たのですが、このままだと重複したものが一つにまとめられて出力してしまっている気がします。
    例えば、
    f1が
    123457465786 134354365436 435435 341535 12344 1123456 343534
    156457465786 134354365436 635435 341535 12044 1123456 343534
    と6番目のデータが同じ時、それが一つとしてカウントされている可能性はありますか?わかりにくくて申し訳ありません、、、伝わりましたでしょうか?

    キャンセル

  • 2017/11/08 22:26

    最後にも書きましたが、keyとなる部分(これがf1の6番目に相当します)が一意的ではない(重複するものがあると)とvalueは最後に出現したものに更新されていきます。

    ですので、f1の6番目の数字が一度でもf2に登場するものに対して、そのf1の行を書き出したい場合、f1に対して辞書を作るのではなく、f2に対して作るべきです。
    それを行っているコードは①のものになります。

    また速度が気になるのであれば、

    hoge_dict = set([k.rstrip() for k in f2]) #f2の重複しない数を抽出
    f1 = filter(None, [l.rstrip() for l in f1]) #f1の空行を削除
    txts = [l for l in f1 if l.split()[5] in hoge_dict] #条件(f1の6番目がf2に出現)に合う行の抽出
    f3.write('\n'.join(txts)) #書き出し

    のようにリスト内包表記で書くと早くなります。

    おまけ:
    残るボトルネックはif l.split()[5] in hoge_dictにあって、hoge_dictが非常に大きい場合マッチングに時間がかかります。
    これは常套手段として、予め並び替えなどをすることによって、2分探索することで早くする余地があります。

    キャンセル

  • 2017/11/08 22:33

    お返事ありがとうございます!最後のアドバイスはそういう意味だったのですね、勘違いしていました。ありがとうございます。
    コード1にこのコード2のtry分を入れる場合どのようにすれば良いのでしょうか?無知で申し訳ありません。また;区切りがタブ区切りになるのはitems = line.split(';')を書き換えれば良いでしょうか?また、他に書き換える部分はありますでしょうか?

    あらかじめ並べ替えとは、ソートコマンドで行ってからということですか?それなら自分にもできそうです!

    キャンセル

  • 2017/11/08 22:44 編集

    コード1:遅い版(インデントが壊れますね…)
    hoge_set = set([])
    for line in f2:
    key = line.rstrip()
    hoge_set.add(key)
    for line in f1:
    line = line.rstrip()
    items = line.split() #';'削除
    if items[5] in hoge_set: #0->5, and以降削除
    f3.write(line + '\n')
    print(line)

    主な遅い理由:for文を使っていること。print文を使っていること。

    try文が必要なくなるように空行削除を先にやっているので、以下のコードをそのまま実行すればよいです。

    コード2:早い版(インデントはこれで正しいです)
    hoge_dict = set([k.rstrip() for k in f2]) #f2の重複しない数を抽出
    f1 = filter(None, [l.rstrip() for l in f1]) #f1の空行を削除
    txts = [l for l in f1 if l.split()[5] in hoge_dict] #条件(f1の6番目がf2に出現)に合う行の抽出
    f3.write('\n'.join(txts)) #書き出し

    キャンセル

  • 2017/11/08 22:58

    ありがとうございます。for文を書かないと早くなるのですね!最初に空行を削除すれば for文を使わずに済むということは思いつきませんでした、他のコードにも応用させていきたいと思います、ありがとうございます!
    これも実行に時間がかかるので完了したらまたご連絡させていただきます。

    キャンセル

  • 2017/11/08 23:03

    txts = [l for l in f1 if l.split()[5] in hoge_dict]
    の行でindex error が出てしまったのですが、どこが原因でしょうか?

    キャンセル

  • 2017/11/08 23:09

    空行だけではなく、数字が6個未満の行があるということだと思います。

    f1 = filter(None, [l.rstrip() for l in f1])

    f1 = [l for l in f1 if len(l.rstrip().split())>=6]
    に変えると動くはずです。

    しかしどのような理由でその行に7個数字がないのかが不明ですが。
    行ずれがどこかで起きているかもしれません。

    キャンセル

  • 2017/11/08 23:19

    ありがとうございます、これでまた実行してみます!

    キャンセル

0

そのインデントで本当に実行しているなら、おそらくそれが原因です。
その書き方だと2重ループになりますので、f1の1行目を処理した時点でf2はEOFまで進んでいるはずです。closeしない限りは、2周目以降は内側のループが実行されないと思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/10/25 21:51

    違うんかいな……

    キャンセル

  • 2017/10/25 21:56

    こちらの回答に目を通していなかったです。ありがとうございます!

    キャンセル

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

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

関連した質問

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

  • Python

    8002questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。