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

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

新規登録して質問してみよう
ただいま回答率
85.51%
Python 3.x

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

Python

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

Q&A

解決済

3回答

4891閲覧

辞書のキーエラー KeyError:

starrow1103

総合スコア137

Python 3.x

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

Python

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

0グッド

1クリップ

投稿2017/03/20 07:54

編集2017/03/20 08:06

やろうとしていること

・指定した辞書のキーと同じ名前のファイルが存在する
・ファイルの存在するディレクトリからファイル名を取得し、
・ファイル名と一致した辞書のキーを選択し表示する

folder
┗マイノリティーリポート
┗ヘルプ 心がつなぐストーリ
...といったフォルダが存在します

辞書

python

1dic = {'マイノリティ・リポート':1, 'ヘルプ 心がつなぐストーリー':2}

ここで、「ヘルプ 心がつなぐストーリー」の値を取得したい

エラー内容

python

1#普通に直打ちすれば取得できる 2print(dic["ヘルプ 心がつなぐストーリー"]) 3>>2

しかし、

python

1#以下でファイル名「ヘルプ 心がつなぐストーリー」が取得できるとします 2f_name = select_file() 3print(f_name) 4>>ヘルプ 心がつなぐストーリー 5 6#こいつでkeyを指定するとエラー 7print(dic[f_name]) 8>>KeyError: 'ヘルプ 心がつなぐストーリー'

##困っていること
ファイル名は正しく取得できているのに、後者の場合ではなぜえらーとなるのか見当がつきません・・・。

スペースが問題ではないかとか、いろいろ試したがわからず・・・

解決策をご存知の方いらっしゃいましたら、ご教授ください。

お願いいたします。

追記 select_file()の中身

python

1def select_file(): 2 d = "folder" 3 file_list = os.listdir(d) 4 #フォルダのリストを表示して、入力した番号のファイル名を取得 5 for i in range(len(file_list)): 6 print("%s:%s" % (i,file_list[i])) 7 f_name = file_list[int(input("番号を選択:"))] 8 return f_name

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2017/03/20 08:01

select_file() の中身を書いてください。
guest

回答3

0

ベストアンサー

実行している環境はMacですか?

以下のURLにあるように、Unicodeの文字正規化には2種類あり、「正規形 C と正規形 D」といいます。
https://docs.python.jp/3/library/unicodedata.html#unicodedata.normalize

MacOSでは、正規形 Dが採用され、カタカナの濁点、半濁点が別々の文字として扱われています。
file_list[i] の文字列の長さを取得すると、濁点部分が多くカウントされると思います。
(または、 file_list[i].encode(utf-8) と bytes型に変換して比べるとわかりやすいかもしれません)

これらを統一化するには、2種類ある正規形のどちらかに揃える必要があります。
私は、 正規形 Cに揃えることが多いです。

Pythonには、 先に示したURLの標準ライブラリ unicodedata にnormalize関数で変換できます。

以下のように変換できます。

import unicodedata filename = unicodedata.normalize('NFKC', file_list[0)

'NFKC' というformを使って、互換分解を適用してから、標準分解を適用しています。

投稿2017/03/20 09:45

terapyon

総合スコア313

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

starrow1103

2017/03/20 09:53

すごい!できました。 Mac特有の問題であったみたいですね。 フォルダ名として登録された時点で、正規形D?のほうに置換されていたんですね。 ということで、フォルダ名から取得した文字列をnormalizeして、辞書キーに割り当てたところ、うまく通りました! ありがとうございました。
terapyon

2017/03/20 09:55

OSによって、どちらが選択されているかが変わります。 WindowsやUbuntuは C なので気にしないことも多いと思います。 参考になり良かったです。
guest

0

ソース中のprintを、以下のようなprint_bytesに置き換えて、dic内のマイノリティ・リポートと、ファイル名のマイノリティ・リポートが厳密に同じ文字かを確認してみてはいかがでしょうか?

Python

1# utf-8に変換した結果(バイト列)をprint 2def print_bytes(s): 3 print(list(s)) # ['マ', 'イ', 'ノ', 'リ', 'テ', 'ィ', '・', 'リ', 'ホ', '゚', 'ー', 'ト'] 4 print(s.encode('utf-8')) # b'\xe3\x83~ 5 6# b'\xe3\x83\x9e\xe3\x82\xa4\xe3\x83\x8e\xe3\x83\xaa\xe3\x83\x86\xe3\x82\xa3\xe3\x83\xbb\xe3\x83\xaa\xe3\x83\x9d\xe3\x83\xbc\xe3\x83\x88' 7# と出力される 8print_bytes("マイノリティ・リポート")

投稿2017/03/20 09:23

編集2017/03/20 09:46
can110

総合スコア38230

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

starrow1103

2017/03/20 09:29

おぉ、 試したところ、厳密に違いました。 辞書の「マイノリティ・リポート」 b'\xe3\x83\x9e\xe3\x82\xa4\xe3\x83\x8e\xe3\x83\xaa\xe3\x83\x86\xe3\x82\xa3\xe3\x83\xbb\xe3\x83\xaa\xe3\x83\x9d\xe3\x83\xbc\xe3\x83\x88' フォルダ名の「マイノリティ・リポート」 b'\xe3\x83\x9e\xe3\x82\xa4\xe3\x83\x8e\xe3\x83\xaa\xe3\x83\x86\xe3\x82\xa3\xe3\x83\xbb\xe3\x83\xaa\xe3\x83\x9b\xe3\x82\x9a\xe3\x83\xbc\xe3\x83\x88' な、なんなんですかこの違いは。。。
can110

2017/03/20 09:47

すでに他の方の回答がついているように、MacOS上でのファイル名の問題のようですね。
guest

0

以下の通り試してみましたが、正常に動作しました。
一度これだけで試してみて、もしうまくいくようなら書かれてない部分に問題があるのではないかと思います。

Python

1import os 2 3dic = {'マイノリティ・リポート':1, 'ヘルプ 心がつなぐストーリー':2} 4print(dic["ヘルプ 心がつなぐストーリー"]) 5 6def select_file(): 7 d = "." 8 file_list = os.listdir(d) 9 #フォルダのリストを表示して、入力した番号のファイル名を取得 10 for i in range(len(file_list)): 11 print("%s:%s" % (i,file_list[i])) 12 f_name = file_list[int(input("番号を選択:"))] 13 return f_name 14 15f_name = select_file() 16print(f_name) 17print(dic[f_name])

投稿2017/03/20 08:19

Zuishin

総合スコア28656

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

starrow1103

2017/03/20 08:55

回答ありがとうございます。 こちらで試してみましたが、やはりKeyErrorとなってしまいます・・・。なんででしょうかね。 ``` Traceback (most recent call last): File "test.py", line 17, in <module> print(dic[f_name]) KeyError: 'ヘルプ 心がつなぐストーリー' ```
starrow1103

2017/03/20 09:02

追記です、 dic = dic = {'マイノリティ・リポート':1,'ヘルプ 心がつなぐストーリー':2,'モールス':3,"湯を沸かすほどの熱い愛":4} として、フォルダを新たに「モールス」「湯を沸かすほどの熱い愛」を作成し試したところ、こちらの2つはうまくいきました。 しかし、「マイノリティ・リポート」と「ヘルプ 心がつなぐストーリー」は依然ダメです・・。
Zuishin

2017/03/20 09:13

キーによってうまくいくということは、スクリプト自身に問題があるのではなく、登録されているキーが間違っていることが考えられます。 たとえば、空白の全角・半角が違っていたり、マイノリティがマイノリティーだったりするようなことはないですか? ディレクトリ名かキーかどちらかをコピーして他方にペーストし、確実に同じになるようにして試してみてください。
starrow1103

2017/03/20 09:24

試しにフォルダ名をそのままコピーし、辞書に貼り付けたところ、うまくいきました。 ここで不思議なのは、文字列の状態(スペースなど)は全く変わっていないということです。 試しに辞書を二つ作って交互に試してみました dic = {'マイノリティ・リポート':1,'ヘルプ 心がつなぐストーリー':2} dic = {'マイノリティ・リポート':1,'ヘルプ 心がつなぐストーリー':2} 上が、オリジナルです。下が、フォルダ名からコピーして作成したものです。 #でコメントアウトして交互に試したところ、上はエラー、下はOKでした。 不思議ですね。 ちなみに、フォルダ名と辞書のキーは同じ文字列から作成しているはずなんです。 例えばこんな感じで作っています。 name = "タイトル" os.mkdir(name) dic = {} dic[name]=1
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問