回答編集履歴

1 追記

quickquip

quickquip score 8467

2019/04/24 13:32  投稿

何が起こっている分からないので、何を確認するか、という話だけ。
----
print関数のデコードの影響を受けないように、`print(data)` のところを `print(data.encode('unicode_escape'))` として、文字列に実際に**どんなコードポイントで格納されているか**を確認する。
実行例
```plain
% echo -n 'ふ' | python -c 'import sys; print(sys.stdin.read().encode("unicode_escape"))'
b'\\u3075'
```
(注: 長さ6のバイト列です)
----
エンコード/デコードの影響を受けないように、
```python
data = sys.stdin.read()
print(data)
```
```python
data = sys.stdin.buffer.read()
print(data)
```
として、バイト列に実際に**どんなデータが格納されているか**を確認する。
実行例
```plain
% echo -n 'ふ' | python -c 'import sys; print(sys.stdin.buffer.read())'
b'\xe3\x81\xb5'
```
(注: 長さ3のバイト列です)
----
どんな結果になるでしょうか?
エンコード/デコード関連のトラブルだと、`print(data)`して`{"text":"ふぇふぇふぇ"}`が出たからといって安心できなくて、`"`と`ふ`の間に不可視文字があるんじゃないの? などを疑ったりしないといけないので、コードポイントやバイナリデータを見るようにしましょう。
```plain
% python -c 'print("ふ")'
% python -c 'print("\uFEFFふ")'
(↑ゼロ幅空白\uFEFFが一見して区別できない)
% python -c 'print("ふ".encode("unicode_escape"))'
b'\\u3075'
% python -c 'print("\uFEFFふ".encode("unicode_escape"))'
b'\\ufeff\\u3075'
```  
 
----  
KSwordOfHaste さんの回答の続きのような形になりますが、  
 
```plain  
% echo -n 'あ' | LANG=C python -c 'import sys; print(sys.stdin.read().encode("unicode_escape"))'  
b'\\udce3\\udc81\\udc82'  
% LANG=C python -c 'import sys; print(sys.stdin.encoding, sys.stdout.encoding)'  
US-ASCII US-ASCII  
```  
`LANG=C` の設定下だと`sys.stdin`の方も US-ASCII encoding になる影響を受けるので、  
 
```python  
sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding="utf-8")  
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")  
```  
とするのがいいようです。  
 
```plain  
% echo -n 'あ' | LANG=C python -c 'import io, sys; sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding="utf-8"); print(sys.stdin.read().encode("unicode_escape"))'  
b'\\u3042'  
```

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る