Skip to content

Commit ddcb8ed

Browse files
committed
finish first version draft
Signed-off-by: sunus <[email protected]>
1 parent 5153164 commit ddcb8ed

File tree

2 files changed

+169
-32
lines changed

2 files changed

+169
-32
lines changed

encode_or_decode_write.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/env python
2+
# encoding=utf-8
3+
4+
import sys
5+
import os
6+
import traceback
7+
8+
sstr1 = "Most Normal String\n"
9+
sstr2 = "我是str string\n"
10+
ustr1 = u"unicode string WITHOUT Chinese\n"
11+
ustr2 = u"我是unicode string\n"
12+
13+
def test(new_file_name, method, *args):
14+
try:
15+
with open(new_file_name, 'w') as f:
16+
for s in args:
17+
so = s
18+
s = getattr(s, method)('utf-8')
19+
f.write(s)
20+
print 'write', so, [so], method, 'succeed!'
21+
print '%s to %s' % (str(so.__class__), str(so.__class__))
22+
except:
23+
traceback.print_exc()
24+
25+
def main():
26+
if sys.argv[1] == 'encode':
27+
test('str', 'encode', sstr1, sstr2)
28+
test('uni', 'encode', ustr1, ustr2)
29+
elif sys.argv[1] == 'decode':
30+
test('str', 'decode', sstr1, sstr2)
31+
test('uni', 'decode', ustr1, ustr2)
32+
else:
33+
print 'arg can only be decode or encode'
34+
35+
main()

pyutf8.md

Lines changed: 134 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,55 +2,157 @@
22

33
######Python的UTF-8编码问题比较让人抓狂, 我之前抓狂过很多次之后决定写一个wiki,
44
######主要是为了解决我们在Python编码过程中遇到的UTF-8中文乱码问题.
5-
######PS: 本WIKI不会对UTF-8具体的细节进行过多的说明, 主要是提供各种不同的情况情况该如何解决提供一些方法.
5+
######PS1: 本WIKI不会对UTF-8具体的细节进行过多的说明, 主要是提供各种不同的情况情况该如何解决提供一些方法.
6+
######PS2: 图省事的话直接看第4点以及conclusion即可:)
67

7-
#### 1. 关于文件的编码:
8+
#### 1. 文件编码
89

9-
* 文件的编码方式是什么?ASCII(default)还是其他的?在vim下可以用:set fileencoding查看.
10+
* 文件的编码方式是什么?ASCII(default)还是其他的?在vim下可以用:set fileencoding查看.
1011
或者使用iconv: iconv -f utf8 filename 如果输出正常, 无错误, 无乱码, 那么该文件也应该是正确地以UTF-8的编码方式保存的.
1112
如果打算使用utf编码,可以使用:set fileencoding=utf8进行指定,vim会负责完成转换工作.
1213

13-
* 关于 [PEP-0263] [1]建议是在文件的头两行显示指定文件编码,方式有如下几种:
14+
* 关于 [PEP-0263] [1]建议是在文件的头两行显示指定文件编码,方式有如下几种:
1415

15-
> 1. `# coding=<encoding name>`
16-
2. `# -*- coding: <encoding name> -*-`
17-
3. `# vim: set fileencoding=<encoding name> :`
18-
19-
> > 第3种比较少见,第2种比较漂亮,第1种是我使用的:)
16+
* `# coding=<encoding name>`
17+
* `# -*- coding: <encoding name> -*-`
18+
* `# vim: set fileencoding=<encoding name> :`
19+
* 第2种比较少见,第1种比较漂亮,第0种是我使用的:)
2020

21-
* 文件编码的作用
21+
* 文件编码的作用
2222

23-
> 1. 让阅读代码的人直到该文件的编码方式
24-
2. 如果文件中有--显式--的需要特别编码处理的字符(如中文)时,通过指定文件的编码能够让editor知道如何处理,储存.
25-
3. 显式具体指的是:
23+
* 让阅读代码的人直到该文件的编码方式
24+
* 如果文件中有--显式--的需要特别编码处理的字符(如中文)时,通过指定文件的编码能够让editor知道如何处理,储存.
25+
* 显式具体指的是:
26+
* a = "我是中文"
27+
* a = u"我是中文"
28+
* Example:
2629

27-
> > * a = "我是中文"
28-
* a = u"我是中文"
29-
30-
* Example: `1-pyutf8.py`
3130

3231
```python
33-
#!/usr/bin/env python
34-
# encoding=utf-8
35-
import os
36-
import sys
37-
a = "我是中文"
38-
b = u"我也是中文"
39-
os.write(sys.stdin.fileno(), a)
40-
os.write(sys.stdin.fileno(), b)
41-
print a
42-
print b
32+
File: 1-pyutf8.py
33+
34+
#!/usr/bin/env python
35+
# encoding=utf-8
36+
import os
37+
import sys
38+
a = "我是中文"
39+
b = u"我也是中文"
40+
os.write(sys.stdin.fileno(), a)
41+
os.write(sys.stdin.fileno(), b)
42+
print a
43+
print b
4344
```
4445

45-
> 若缺少了了# encoding=utf-8 则文件在 执行时会出错:
46+
* 若缺少了了# encoding=utf-8 则文件在 执行时会出错: `SyntaxError: Non-ASCII character '\xe6' in file 1-pyutf8.py on line 5, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details`
47+
48+
* 此时是Python解析器报的错误,而出错的原因正是Python解析器没有找到合适的编码方法去解析代码. 注意:
49+
此时,编码文件已经是正确地已UTF-8格式储存的, 只是Python不知道.所以需要显示地进行指定.
50+
51+
* 另外,关于使用print/os.write, print会根据终端的环境进行一些编码换转, 或许会"欺骗"我们, os.write的结果则是比较准确, 真实的.
4652

47-
> `SyntaxError: Non-ASCII character '\xe6' in file 1-pyutf8.py on line 5, but no encoding declared;
48-
see http://www.python.org/peps/pep-0263.html for details`
53+
* trick: 我们可以将字符串放如一个集合类型中,比如list. 然后再使用print打印该list, 这样可以得到真实的数据类型.
4954

50-
> 此时是Python解析器报的错误,而出错的原因正是Python解析器没有找到合适的编码方法去解析代码. 注意: 此时,编码文件已经是正确地已UTF-8格式储存的, 只是Python不知道.所以需要显示地进行指定.
55+
```python
56+
>>> a = "中文"
57+
>>> b = u"中文"
58+
>>> c = u"sunus"
59+
>>> print a, b, c
60+
中文 中文 sunus
61+
>>> print [a, b, c]
62+
['\xe4\xb8\xad\xe6\x96\x87', u'\u4e2d\u6587', u'sunus']
63+
```
5164

52-
> 另外,关于使用print/os.write, print会根据终端的环境进行一些编码换转, 或许会"欺骗"我们, os.write的结果则是比较准确, 真实的.
65+
* 第二个print的结果可以知道, a为str, b, c均为unicode. 而第一个print则不会显示这些信息.
66+
5367

5468
* 在确定文件编码之后没问题之后,继续分析别的错误.
5569

70+
71+
#### 2. unicode , str and UTF-8
72+
73+
* python2x里, 对于字符串有两个不同的类进行表示,分别是 __unicode____str__, 对应的Constructor分别是unicode(), str(), 而且, 他们都是由同一个基类 __basestring__ 派生出来的. 顺便说一下,检验一个对象的正确方法是
74+
`isinstance(value, basestring)`
75+
76+
* unicode是为了处理多字节字符(如中文)而设计的, 对于ASCII字符来说, 他们没什么区别而且能够兼容, 但是, 当有出现中文时, 问题就出来了.
77+
* UTF-8是一个具体的unicode编码方式的实现.
78+
* 我们将 __str__ 作为 __可读__ 的字符串, unicode作为python内部对字符串的一种 __抽象__ 实现并选择正确的储存方法, print var, 'xx', "xxx" 则都是str(没有打头的u)
79+
80+
#### 3. encode and decode
81+
82+
* __encode__: 是将unicode转换成str编码, 并且encoding参数为具体的实现, 如UTF-8
83+
* __decode__: 是将str转换成unicode编码, 并且encoding参数为具体的实现, 如UTF-8
84+
85+
* 使用建议:
86+
* 对于unicode 尽量只让unicode对象存在于内存中, __打印输出__, __网络传输__, __写入文件__, __之前__ 应该将其转换为 str, 而且,
87+
含有非ASCII码字符的unicode字符串, 是 __写不进文件__ 的.
88+
* 以str字符串形似, 或者通过外部手段(iconv, vim set fileencoding, etc)等方式形成的文件, 本身就能够 __无障碍__ 地被读取.
89+
* unicode字符串, 只作为"中间态"使用.如
90+
91+
```python
92+
a = u'OnlyIn内存'
93+
#if you want to see what's in a
94+
#use:
95+
ae = a.encode('utf8')
96+
#do whatever you want with a, net transporat or write to file.
97+
```
98+
* 无encoding参数的encode, decode方法所使用的默认encoding为系统环境获取, 不建议使用.
99+
100+
101+
#### 4. Examples:
102+
103+
```python
104+
File: encode_or_decode_write.py
105+
106+
#!/usr/bin/env python
107+
# encoding=utf-8
108+
109+
import sys
110+
import os
111+
import traceback
112+
113+
sstr1 = "Most Normal String\n"
114+
sstr2 = "我是str string\n"
115+
ustr1 = u"unicode string WITHOUT Chinese\n"
116+
ustr2 = u"我是unicode string\n"
117+
118+
def test(new_file_name, method, *args):
119+
try:
120+
with open(new_file_name, 'w') as f:
121+
for s in args:
122+
so = s
123+
s = getattr(s, method)('utf-8')
124+
f.write(s)
125+
print 'write', so, [so], method, 'succeed!'
126+
print '%s to %s' % (str(so.__class__), str(so.__class__))
127+
except:
128+
traceback.print_exc()
129+
130+
def main():
131+
if sys.argv[1] == 'encode':
132+
test('str', 'encode', sstr1, sstr2)
133+
test('uni', 'encode', ustr1, ustr2)
134+
elif sys.argv[1] == 'decode':
135+
test('str', 'decode', sstr1, sstr2)
136+
test('uni', 'decode', ustr1, ustr2)
137+
else:
138+
print 'arg can only be decode or encode'
139+
140+
main()
141+
```
142+
143+
* 执行 python encode_or_decode_write.py encode , sstr1, ustr1, ustr2 能够成功写入文件, sstr2 失败.
144+
* 对unicode使用encode使之变成可读, 可写, 可传输的str. 所以 ustr1, ustr2 均成功.
145+
* sstr1因为没有包含非ASCII字符, 所以也成功了. 而sstr1包含有中文, 失败. __一定, 一定不要使用unicode进行读写, 传输等操作__
146+
147+
* 执行 python encode_or_decode_write.py decode , 只有sstr1, ustr1 能够成功写入, 因为他们没有非ASCII字符.
148+
* sstr2, decode之后变为unicode 该过程成功,失败是因为将unicode __写入文件__
149+
* ustr2, decode则直接失败了, 对unicode进行decode操作, 本身就是有问题的嘛!
150+
151+
#### 5. Conclusion:
152+
* 将unicode留在内存中
153+
* 读取, 写入文件, 网络传输使用str. 即
154+
str_str = unicode_string.encode('utf8')
155+
156+
#### 6. 有错误, 不清楚的地方欢迎请指出, 谢谢:)
157+
56158
[1]: http://www.python.org/dev/peps/pep-0263/ "PEP-0263"

0 commit comments

Comments
 (0)