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

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

ただいまの
回答率

90.98%

  • Python

    5567questions

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

Pythonで¥uコードの変換

解決済

回答 4

投稿 編集

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

kuniatsu

score 77

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しか方法がないので主旨を変えて質問いたします。よろしくお願いします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 4

+2

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

でどうでしょうか?

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

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/01/25 16:23 編集

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

    キャンセル

checkベストアンサー

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である前提です。

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

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

import locale
locale.getpreferredencoding()


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

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

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/01/25 11:34

    解答内の「locale.getpreferredencoding()」の件は
    https://qiita.com/megmogmog1965/items/05a6c48a9a5e64a611f4
    をみてコメントしておりますが本来はpython 2の仕様の方をみるべきと思います。ちょっとサボりました。

    キャンセル

  • 2018/01/26 01:14

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

    キャンセル

0

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

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

以下、以前の回答

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

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

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

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

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

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

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

# 任意エンコード文字列をunicode文字列に自動変換
# https://qiita.com/zarchis/items/3258562ebc9570fa05a3
def conv_encoding(s):
    encs = (
        # jis系から先に試す
        # http://d.hatena.ne.jp/kakurasan/20100330/p1
        'iso2022jp', 'iso2022_jp_1', 'iso2022_jp_2', 'iso2022_jp_3', 'iso2022_jp_ext',
        'utf_8',
        'euc_jp', 'euc_jis_2004', 'euc_jisx0213',
        'shift_jis', 'shift_jis_2004','shift_jisx0213',
        'latin_1', 'ascii')
    for enc in encs:
        try:
            us = s.decode(enc)
            if isinstance( us, unicode):
                # 念のため再エンコードし一致判定
                ds = us.encode(enc)
                if s == ds:
                    return us,enc
        except:
            pass

    raise LookupError

import sys
inp = sys.stdin.readline()
(uni_s,enc) = conv_encoding(inp)
#sys.stderr.write(enc+'\n')
u8_s = uni_s.encode('utf-8')
sys.stdout.write( u8_s)

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

$ od -Ax -tx1z iso2022jp.txt
000000 1b 24 42 25 6c 25 36 21 3c 1b 28 42              >.$B%l%6!<.(B<
00000c
$ python temp.py < iso2022jp.txt > ret.txt
iso2022jp
od -Ax -tx1z ret.txt
000000 e3 83 ac e3 82 b6 e3 83 bc                       >.........<
000009

$ od -Ax -tx1z utf8.txt
000000 e3 83 ac e3 82 b6 e3 83 bc                       >.........<
000009
$ python temp.py < utf8.txt > ret.txt
utf_8
$ od -Ax -tx1z ret.txt
000000 e3 83 ac e3 82 b6 e3 83 bc                       >.........<
000009

$ od -Ax -tx1z eucjp.txt
000000 a5 ec a5 b6 a1 bc                                >......<
000006
$ python temp.py < eucjp.txt > ret.txt
euc_jp
$ od -Ax -tx1z ret.txt
000000 e3 83 ac e3 82 b6 e3 83 bc                       >.........<
000009

$ od -Ax -tx1z sjis.txt
000000 83 8c 83 55 81 5b                                >...U.[<
000006
$ python temp.py < sjis.txt > ret.txt
shift_jis
$ od -Ax -tx1z ret.txt
000000 e3 83 ac e3 82 b6 e3 83 bc                       >.........<
000009

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/01/26 15:21

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

    キャンセル

  • 2018/01/26 15:32

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

    キャンセル

0

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

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

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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

  • Python

    5567questions

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