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

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

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

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

Q&A

解決済

4回答

520閲覧

Pythonで¥uコードの変換

kuniatsu

総合スコア141

Python

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

0グッド

0クリップ

投稿2018/01/25 01:38

編集2018/01/25 01:39

catコマンド単体では文字コードの変換がうまく行われますが、それを複製するとエラーが出ます。

$ cat text \u30ec\u30b6\u30fc
$ cat text |python -c 'from sys import stdin; print stdin.readline().decode("unicode-escape")' レザー

こちらは正常に変換

$ cat text |python -c 'from sys import stdin; print stdin.readline().decode("unicode-escape")' > text2 Traceback (most recent call last): File "<string>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)

コピーするとエラーが発生

$ python -c 'from sys import stdin; print stdin.readline().decode("unicode-escape")' < text > text2 Traceback (most recent call last): File "<string>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)

別の書き方でも

文字コードをエンコードして保存したいのですが、何か方法はありませんか?

昨日こちらの質問をしました
https://teratail.com/questions/110464
Pythonしか方法がないので主旨を変えて質問いたします。よろしくお願いします。

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

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

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

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

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

guest

回答4

0

bash

1$ cat text | PYTHONIOENCODING=utf-8 python -c (以下略)

でどうでしょうか?

参考URL: Python2で文字列を処理する際の心掛け

投稿2018/01/25 07:06

fuzzball

総合スコア16731

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

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

KSwordOfHaste

2018/01/25 07:23 編集

自分の環境ではfuzzballさんの方法を用いるとprint時にencodeしなくても動きました。 locale.getpreferredencoding()が"UTF-8"となっているだけでは動かず PYTHONIOENCODING=utf-8と設定しておくと動くということは リダイレクトされてstdoutがttyでない場合pythonがpreferred encodingではないエンコーディングを仮定するということなのでしょうね。その仮定を明示的に指示する方法の一つが PYTHONIOENCODINGということになるのでしょうか・・・記事を見るとそんな感じですかね。
guest

0

Pythonは、Unicode文字列の別の型があります。decode結果は普通の文字列なので、Unicode型に変換する必要があるようです。

Bash

1echo '\u30ec\u30b6\u30fc' | 2python -c 'from sys import stdin; print stdin.readline().decode("unicode-escape").encode("utf-8")' > out.txt

投稿2018/01/25 07:09

otn

総合スコア84423

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

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

0

元データ内容について誤解釈しており、完全に間違った回答をしていました。
失礼しました。

標準入力で受け取るのはユニコードエスケープ形式の文字列であり、これは
stdin.readline().decode("unicode-escape")により正しくunicode文字列に変換されます。
しかし次の出力処理 printにおいて、出力先がターミナル(端末)では正常に動作していますが、出力先がファイルの場合にエラーが発生しています。
その原因および対応法はfuzzballさんの回答に示されているリンク先が正しいかと思います。

以下、以前の回答

まず、catコマンドは文字コードの変換はおこないません。
textの内容が、ユニコードエスケープ(\uxxxx)されて表現(出力)されているにすぎません。

元データのエンコーディングが判っておりiconvが入っていれば、以下のように任意のエンコーディングに変換できます。

PlainText

1$ which iconv 2/home/hoge/anaconda3/bin/iconv 3$ iconv -f UTF-16LE -t UTF-8 text > utf-8.txt 4$ od -Ax -tx1z ret.txt 5000000 e3 83 ac e3 82 b6 e3 83 bc >.........< #「レザー」のUTF-8表現 6000009

元データのエンコーディングが判らない場合はchardetをインストールすることでエンコーディングを自動判別できるので、以下のようなコードで変換できます。
ただし、この手法の限界として、誤判定する可能性が多分にあります。

Python

1import sys 2import chardet 3inp = sys.stdin.readline() 4det = chardet.detect(inp) 5uni_s = inp.decode(det['encoding']) # 失敗する可能性あり 6u8_s = uni_s.encode('utf-8') 7sys.stdout.write( u8_s)

また、どうしても素のPython2.xでやる必要があれば、以下のようなコードでも、それなりにできます。
元データを片っ端からデコード→再エンコードしてみて成功(元データと一致)したエンコーディングを採用するという手法です。

参考:
テキストファイルのエンコーディングを自動判定して処理する
Pythonにおける日本語のエンコーディングの検出について

Python

1# 任意エンコード文字列をunicode文字列に自動変換 2# https://qiita.com/zarchis/items/3258562ebc9570fa05a3 3def conv_encoding(s): 4 encs = ( 5 # jis系から先に試す 6 # http://d.hatena.ne.jp/kakurasan/20100330/p1 7 'iso2022jp', 'iso2022_jp_1', 'iso2022_jp_2', 'iso2022_jp_3', 'iso2022_jp_ext', 8 'utf_8', 9 'euc_jp', 'euc_jis_2004', 'euc_jisx0213', 10 'shift_jis', 'shift_jis_2004','shift_jisx0213', 11 'latin_1', 'ascii') 12 for enc in encs: 13 try: 14 us = s.decode(enc) 15 if isinstance( us, unicode): 16 # 念のため再エンコードし一致判定 17 ds = us.encode(enc) 18 if s == ds: 19 return us,enc 20 except: 21 pass 22 23 raise LookupError 24 25import sys 26inp = sys.stdin.readline() 27(uni_s,enc) = conv_encoding(inp) 28#sys.stderr.write(enc+'\n') 29u8_s = uni_s.encode('utf-8') 30sys.stdout.write( u8_s)

WSL(Windows Subsystem for Linux)での検証結果

PlainText

1$ od -Ax -tx1z iso2022jp.txt 2000000 1b 24 42 25 6c 25 36 21 3c 1b 28 42 >.$B%l%6!<.(B< 300000c 4$ python temp.py < iso2022jp.txt > ret.txt 5iso2022jp 6od -Ax -tx1z ret.txt 7000000 e3 83 ac e3 82 b6 e3 83 bc >.........< 8000009 9 10$ od -Ax -tx1z utf8.txt 11000000 e3 83 ac e3 82 b6 e3 83 bc >.........< 12000009 13$ python temp.py < utf8.txt > ret.txt 14utf_8 15$ od -Ax -tx1z ret.txt 16000000 e3 83 ac e3 82 b6 e3 83 bc >.........< 17000009 18 19$ od -Ax -tx1z eucjp.txt 20000000 a5 ec a5 b6 a1 bc >......< 21000006 22$ python temp.py < eucjp.txt > ret.txt 23euc_jp 24$ od -Ax -tx1z ret.txt 25000000 e3 83 ac e3 82 b6 e3 83 bc >.........< 26000009 27 28$ od -Ax -tx1z sjis.txt 29000000 83 8c 83 55 81 5b >...U.[< 30000006 31$ python temp.py < sjis.txt > ret.txt 32shift_jis 33$ od -Ax -tx1z ret.txt 34000000 e3 83 ac e3 82 b6 e3 83 bc >.........< 35000009

投稿2018/01/25 05:55

編集2018/01/26 07:07
can110

総合スコア38233

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

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

otn

2018/01/26 06:21

> textの内容が、ユニコードエスケープ(\uxxxx)されて表現(出力)されているにすぎません。 オプション無しの cat は何の変換も行いませんので、最初からファイルの中身に、エスケープされた文字列が入っています。
can110

2018/01/26 06:32

あああ。元データについて完全に勘違いしてました。 元データの文字列自体が「\u30ec\u30b6\u30fc」というユニコードエスケープ形式だったことに今更気づきました。 > textの内容が、ユニコードエスケープ(\uxxxx)されて表現(出力)されているにすぎません。 の部分でも、こちらの環境では再現せず推測で回答していました。 ご指摘ありがとうございます。 なんだか他の方の回答と違うな~と気にはなってたのですが、後ほど回答も修正しておきます。
guest

0

ベストアンサー

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)

python 2.x系は意識して起動することが少ないのですが・・・
こういうスクリプトにするとうまく出力できるようです。/usr/bin/pythonはpython2.xである前提です。

python

1#!/usr/bin/python 2from sys import stdin 3s = stdin.readline().decode("unicode-escape") 4print s.encode('utf-8')

文字セットに絡む話はややこしいですが、上記でなぜうまくいくか自分にはちゃんと説明できません。python 2.xでのprint時のエンコーディングは

python

1import locale 2locale.getpreferredencoding()

で決まるという記事を見たのですがリダイレクト(> txt2)をしてもしなくても自分の環境ではUTF-8でした。にもかかわらずリダイレクトした場合のみUnicodeEncodeError: 'ascii' codec と出るので、それはつまりprint時のエンコーディングがリダイレクトした場合ではUTF-8ではなくASCIIになっているという事実を示しているのだと思います。

「python 2 print encoding」で詳しく調べてみてはいかがでしょう?

投稿2018/01/25 02:28

編集2018/01/25 02:29
KSwordOfHaste

総合スコア18392

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

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

kuniatsu

2018/01/25 16:14

こちらの.encode('utf-8')でうまく行きましたのでこちらをベストアンサーとさせていただきます。 他、回答くださった皆様ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問