[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
[[ノート/テキストマイニング]]~
訪問者数 &counter(); 最終更新 &lastmod();~
**PythonのUnicode/UTF-8文字列の扱い --- 2012/02/29 [#p2a6cd72]
***UnicodeとUTF-8 [#ff404d5d]
Unicodeは、 [[WikipediaのUnicode:http://ja.wikipedia.org/wiki/Unicode]] によると
世界中の多くのコンピュータ上の文字列を一貫した方法で符号化し、表現し、
扱うためのコンピュータ業界の標準
で、
NT系のMicrosoft Windows (Windows)、Mac OS X、LinuxやJavaなどで利用されて
おり、
元々16ビットの文字集合で全ての文字の網羅を目指して開発されたが、
符号位置が圧倒的に足りなくなり、Unicode 2.0以降では、
21ビットの文字集合として規定されることとなった。
である。
Unicodeの文字を表現する場合、"U+"にその文字の符号位置を表す16進数の値を続ける。
また、
日本の文字については当初より JIS X 0201、JIS X 0208 と JIS X 0212 を、
Unicode 3.1 では JIS X 0213 の内容を収録している。
具体的に我々が使いそうなのは、
U+0000-007F ラテン文字(ASCII文字)
と
U+3000-303F 漢字上の記号・句読点
U+3040-309F ひらがな
U+30A0-30FF かたかな
U+4E00-9FFF 漢字(正確にはCJK統合漢字、CJKは中国・日本・韓国)
と思われる。あと、CJK互換文字とかCJK統合漢字拡張B,C,Dとかあるが、無視してよいのか?
UTF-8は、上記のUnicodeを「符号化」する方法の1つである。[[WikipediaのUTF-8:http://ja.wikipedia.org/wiki/UTF-8]]によると、
ASCII文字と互換性を持たせるために、ASCIIと同じ部分は1バイト、その他の部分
を2〜6バイトで符号化する。4バイトのシーケンスでは21bit(0x1FFFFF)まで
表現することができるが、(後略)
であり、符号化の規則は、
バイトの先頭が0 ⇒ 1バイトコード(ASCII対応のU+00-7Fの部分)
バイトの先頭が10 ⇒ 2〜6バイト時の2〜6バイト目(非1バイト目)を表す
バイトの先頭が110 ⇒ 2バイトコードの1バイト目
2バイトコードはU+0080-07FFを収容する。7FF=11ビットをyyyyxxxxxxxとすると
1バイト目 110yyyyx、 2バイト目 10xxxxxx として収める
バイトの先頭が1110 ⇒ 3バイトコードの1バイト目
3バイトコードはU+08000-FFFFを収容する。FFFF=16ビットをyyyyyxxxxxxxxxxxとすると
1バイト目 1110yyyy、 2バイト目 10yxxxxx、 3バイト目 10xxxxxx として収める。
***Pythonでの、Unicode文字列とUTF-8文字列の違い [#x15e1489]
ここは、かなり微妙な話で、わかりにくかったが、[[このページ:http://lab.hde.co.jp/2008/08/pythonunicodeencodeerror.html]]を見て納得した。
要するに、Python上では~
Unicode文字列 = 次項に述べるように、「シーケンス型」のうちの1つで、propertyとして「unicode」がついているもの。だから、
>>> u1 = u"これはユニコード型文字列です"
>>> type(u1)
<type 'unicode'>
UTF-8の文字列 = シーケンス型のうちの「str型」であり、バイト列と思えばよいらしく、その中に入っている文字のエンコードは(pythonとしては)関わらない。たまたまシステムがUTF-8を仮定しているのでUTF-8のバイトコードが入っているだけ。
>>> s1 = "これはふつうの文字列です"
>>> type(s1)
<type 'str'>
Pythonのシステムに対して、「扱う文字コードはUTF-8」としておけば(=プログラム上に書く文字列も、入出力もUTF-8としておけば)、str型の中に入っている文字列はUTF-8になっている。でも、ユニコード型とは、同じものではない。また、ユニコード型の文字列が内部的にUTF-8で表現されている保証もない(実際どうなのか知らない)。
目に見える違いとしては、たとえば
# EUC-JPなソースコードでは
>>> len("あ") 〜〜〜 EUC-JPやShift-JISでは2バイトで保持される
2
# UTF-8なソースコードでは
>>> len("あ") 〜〜〜 UTF-8では3バイトで保持される
3
# unicode型なら
>>> len(u"あ") 〜〜〜 ユニコード文字としては1文字(内部表現のバイトではなくて)
1
ということになる。
で、基本は、プログラム内部ではなるべくunicode型で持つべし、ということになる。変換が必要になることがある。
-プログラム内に文字列で書くときは、u"あいうえお"のようにuを付けるとunicode型になり、またuを付けずに"かきくけこ"のように書くとstr型になる。
-標準入出力については、
import sys
import codecs
sys.stdin = codecs.getreader('utf_8')(sys.stdin)
sys.stdout = codecs.getwriter('utf_8')(sys.stdout)
を使う。同様にファイル入出力に対しては
import codecs
fin = codecs.open('input.txt', 'r', 'utf_8')
fout = codecs.open('output.txt', 'w', 'utf_8')
のようにすることができる。なお、utf_8の代わりにshift_jisやeuc_jpを指定することもできる。
-変数間で変換するには、
u1 = u"あいう" 〜〜〜 u1はunicode型
s1 = u1.encode('utf_8') 〜〜〜 s1はstr型
や、逆に
s1 = "かきく" 〜〜〜 s1はstr型
u1 = s1.decode('utf_8') 〜〜〜 u1はunicode型
ができる。また組込み関数unicodeはdecode('utf_8')と同じような働きをする
u1 = unicode(s1, 'utf_8')
ができる。
***Pythonでのunicode文字列とその分解 [#a2923808]
まず、Pythonでのunicode文字列は、「シーケンス型」である。([[5.6節 シーケンス型:http://www.python.jp/doc/release/library/stdtypes.html#str-unicode-list-tuple-bytearray-buffer-xrange]])
シーケンス型への操作は、この5.6節の表に載っている通りで、
|x in s|s のある要素 x と等しい場合 True , そうでない場合 False|
|x not in s|s のある要素が x と等しい場合 False, そうでない場合 True|
|s + t| s および t の結合|
|s * n, n * s|s の浅いコピー n 個からなる結合 |
|s[i]|s の 0 から数えて i 番目の要素|
|s[i:j]|s の i 番目から j 番目までのスライス|
|s[i:j:k]|s の i 番目から j 番目まで、 k 毎のスライス|
|len(s)|s の長さ |
|min(s)|s の最小の要素 |
|max(s)|s の最大の要素|
|s.index(i)|s 中で最初に i が現れる場所のインデクス |
|s.count(i)|s 中に i が現れる数|
だから、s[i]を使って文字列を先頭からスキャンして判定することになる。
Pythonでの、文字列がUnicodeであるかどうかの判定は、実は簡単で、
1文字ずつスキャンする必要はない。シーケンス型の変数xがUnicodeであるかどうかは、
isinstance(x, unicode)
によって判定できる。
しかし、これは今の役には立たない。なぜなら、Twitter APIで得られたtext本文は、
すべて(ASCII文字も含めて)Unicodeで書かれているからである。たとえば、 u'abc'
など。従って、ASCII文字であるか漢字(2バイトコード)であるかの区別は、
1文字ずつ判定をする必要がある。
実際に欲しいのは、文字列全体の中に漢字(2バイトコード)が含まれているか否か、であるから、1文字でも漢字が出てくればそこでTrueを返せばよい。全部の文字を確認する必要はない。つまり
Unicode文字列であることを確認したうえで、
先頭から1文字ずつ見て行って、
もしord(文字)が30xxや4Exx-9xxxならば、それは漢字なので「漢字入り文字列」。
もし最後のバイトまでそうでなければ、「ASCII文字列」
である。
# -*- coding: utf-8 -*-
def hasKanji(s):
#Returns True if string s contains a Kanji, False if not.
kanji = False
for c in s:
if (((ord(c)&0xff00) == 0x3000) or (0x4e00 <= ((ord(c)&0xff00) <=0x9f00))):
kanji = True
break
return kanji
s = u"abc" とか u"abcあ" とか
print hasKanji(s)
***Twitter APIとhasKanjiを組み合わせる [#o7bd152e]
# -*- coding: utf-8 -*-
import twitter
def hasKanji(s):
#Returns True if string s contains a Kanji, False if not.
kanji = False
for c in s:
if (((ord(c)&0xff00) == 0x3000) or (0x4e00 <= ((ord(c)&0xff00) <=0x9f00))):
kanji = True
break
return kanji
api = twitter.Api()
timeline = api.GetPublicTimeline()
for s in timeline:
t = s.text
if hasKanji(t):
print "Kanji> ", t
else:
print "Ascii> ", t
実際やってみると、Kanjiのツイートはそれ程多くないものだ。時間帯によるのか?
次のステップは、選び出した漢字のツイートを日本語形態素解析に掛けることになる ⇒ [[ノート/テキストマイニング/twitter-2]]
終了行:
[[ノート/テキストマイニング]]~
訪問者数 &counter(); 最終更新 &lastmod();~
**PythonのUnicode/UTF-8文字列の扱い --- 2012/02/29 [#p2a6cd72]
***UnicodeとUTF-8 [#ff404d5d]
Unicodeは、 [[WikipediaのUnicode:http://ja.wikipedia.org/wiki/Unicode]] によると
世界中の多くのコンピュータ上の文字列を一貫した方法で符号化し、表現し、
扱うためのコンピュータ業界の標準
で、
NT系のMicrosoft Windows (Windows)、Mac OS X、LinuxやJavaなどで利用されて
おり、
元々16ビットの文字集合で全ての文字の網羅を目指して開発されたが、
符号位置が圧倒的に足りなくなり、Unicode 2.0以降では、
21ビットの文字集合として規定されることとなった。
である。
Unicodeの文字を表現する場合、"U+"にその文字の符号位置を表す16進数の値を続ける。
また、
日本の文字については当初より JIS X 0201、JIS X 0208 と JIS X 0212 を、
Unicode 3.1 では JIS X 0213 の内容を収録している。
具体的に我々が使いそうなのは、
U+0000-007F ラテン文字(ASCII文字)
と
U+3000-303F 漢字上の記号・句読点
U+3040-309F ひらがな
U+30A0-30FF かたかな
U+4E00-9FFF 漢字(正確にはCJK統合漢字、CJKは中国・日本・韓国)
と思われる。あと、CJK互換文字とかCJK統合漢字拡張B,C,Dとかあるが、無視してよいのか?
UTF-8は、上記のUnicodeを「符号化」する方法の1つである。[[WikipediaのUTF-8:http://ja.wikipedia.org/wiki/UTF-8]]によると、
ASCII文字と互換性を持たせるために、ASCIIと同じ部分は1バイト、その他の部分
を2〜6バイトで符号化する。4バイトのシーケンスでは21bit(0x1FFFFF)まで
表現することができるが、(後略)
であり、符号化の規則は、
バイトの先頭が0 ⇒ 1バイトコード(ASCII対応のU+00-7Fの部分)
バイトの先頭が10 ⇒ 2〜6バイト時の2〜6バイト目(非1バイト目)を表す
バイトの先頭が110 ⇒ 2バイトコードの1バイト目
2バイトコードはU+0080-07FFを収容する。7FF=11ビットをyyyyxxxxxxxとすると
1バイト目 110yyyyx、 2バイト目 10xxxxxx として収める
バイトの先頭が1110 ⇒ 3バイトコードの1バイト目
3バイトコードはU+08000-FFFFを収容する。FFFF=16ビットをyyyyyxxxxxxxxxxxとすると
1バイト目 1110yyyy、 2バイト目 10yxxxxx、 3バイト目 10xxxxxx として収める。
***Pythonでの、Unicode文字列とUTF-8文字列の違い [#x15e1489]
ここは、かなり微妙な話で、わかりにくかったが、[[このページ:http://lab.hde.co.jp/2008/08/pythonunicodeencodeerror.html]]を見て納得した。
要するに、Python上では~
Unicode文字列 = 次項に述べるように、「シーケンス型」のうちの1つで、propertyとして「unicode」がついているもの。だから、
>>> u1 = u"これはユニコード型文字列です"
>>> type(u1)
<type 'unicode'>
UTF-8の文字列 = シーケンス型のうちの「str型」であり、バイト列と思えばよいらしく、その中に入っている文字のエンコードは(pythonとしては)関わらない。たまたまシステムがUTF-8を仮定しているのでUTF-8のバイトコードが入っているだけ。
>>> s1 = "これはふつうの文字列です"
>>> type(s1)
<type 'str'>
Pythonのシステムに対して、「扱う文字コードはUTF-8」としておけば(=プログラム上に書く文字列も、入出力もUTF-8としておけば)、str型の中に入っている文字列はUTF-8になっている。でも、ユニコード型とは、同じものではない。また、ユニコード型の文字列が内部的にUTF-8で表現されている保証もない(実際どうなのか知らない)。
目に見える違いとしては、たとえば
# EUC-JPなソースコードでは
>>> len("あ") 〜〜〜 EUC-JPやShift-JISでは2バイトで保持される
2
# UTF-8なソースコードでは
>>> len("あ") 〜〜〜 UTF-8では3バイトで保持される
3
# unicode型なら
>>> len(u"あ") 〜〜〜 ユニコード文字としては1文字(内部表現のバイトではなくて)
1
ということになる。
で、基本は、プログラム内部ではなるべくunicode型で持つべし、ということになる。変換が必要になることがある。
-プログラム内に文字列で書くときは、u"あいうえお"のようにuを付けるとunicode型になり、またuを付けずに"かきくけこ"のように書くとstr型になる。
-標準入出力については、
import sys
import codecs
sys.stdin = codecs.getreader('utf_8')(sys.stdin)
sys.stdout = codecs.getwriter('utf_8')(sys.stdout)
を使う。同様にファイル入出力に対しては
import codecs
fin = codecs.open('input.txt', 'r', 'utf_8')
fout = codecs.open('output.txt', 'w', 'utf_8')
のようにすることができる。なお、utf_8の代わりにshift_jisやeuc_jpを指定することもできる。
-変数間で変換するには、
u1 = u"あいう" 〜〜〜 u1はunicode型
s1 = u1.encode('utf_8') 〜〜〜 s1はstr型
や、逆に
s1 = "かきく" 〜〜〜 s1はstr型
u1 = s1.decode('utf_8') 〜〜〜 u1はunicode型
ができる。また組込み関数unicodeはdecode('utf_8')と同じような働きをする
u1 = unicode(s1, 'utf_8')
ができる。
***Pythonでのunicode文字列とその分解 [#a2923808]
まず、Pythonでのunicode文字列は、「シーケンス型」である。([[5.6節 シーケンス型:http://www.python.jp/doc/release/library/stdtypes.html#str-unicode-list-tuple-bytearray-buffer-xrange]])
シーケンス型への操作は、この5.6節の表に載っている通りで、
|x in s|s のある要素 x と等しい場合 True , そうでない場合 False|
|x not in s|s のある要素が x と等しい場合 False, そうでない場合 True|
|s + t| s および t の結合|
|s * n, n * s|s の浅いコピー n 個からなる結合 |
|s[i]|s の 0 から数えて i 番目の要素|
|s[i:j]|s の i 番目から j 番目までのスライス|
|s[i:j:k]|s の i 番目から j 番目まで、 k 毎のスライス|
|len(s)|s の長さ |
|min(s)|s の最小の要素 |
|max(s)|s の最大の要素|
|s.index(i)|s 中で最初に i が現れる場所のインデクス |
|s.count(i)|s 中に i が現れる数|
だから、s[i]を使って文字列を先頭からスキャンして判定することになる。
Pythonでの、文字列がUnicodeであるかどうかの判定は、実は簡単で、
1文字ずつスキャンする必要はない。シーケンス型の変数xがUnicodeであるかどうかは、
isinstance(x, unicode)
によって判定できる。
しかし、これは今の役には立たない。なぜなら、Twitter APIで得られたtext本文は、
すべて(ASCII文字も含めて)Unicodeで書かれているからである。たとえば、 u'abc'
など。従って、ASCII文字であるか漢字(2バイトコード)であるかの区別は、
1文字ずつ判定をする必要がある。
実際に欲しいのは、文字列全体の中に漢字(2バイトコード)が含まれているか否か、であるから、1文字でも漢字が出てくればそこでTrueを返せばよい。全部の文字を確認する必要はない。つまり
Unicode文字列であることを確認したうえで、
先頭から1文字ずつ見て行って、
もしord(文字)が30xxや4Exx-9xxxならば、それは漢字なので「漢字入り文字列」。
もし最後のバイトまでそうでなければ、「ASCII文字列」
である。
# -*- coding: utf-8 -*-
def hasKanji(s):
#Returns True if string s contains a Kanji, False if not.
kanji = False
for c in s:
if (((ord(c)&0xff00) == 0x3000) or (0x4e00 <= ((ord(c)&0xff00) <=0x9f00))):
kanji = True
break
return kanji
s = u"abc" とか u"abcあ" とか
print hasKanji(s)
***Twitter APIとhasKanjiを組み合わせる [#o7bd152e]
# -*- coding: utf-8 -*-
import twitter
def hasKanji(s):
#Returns True if string s contains a Kanji, False if not.
kanji = False
for c in s:
if (((ord(c)&0xff00) == 0x3000) or (0x4e00 <= ((ord(c)&0xff00) <=0x9f00))):
kanji = True
break
return kanji
api = twitter.Api()
timeline = api.GetPublicTimeline()
for s in timeline:
t = s.text
if hasKanji(t):
print "Kanji> ", t
else:
print "Ascii> ", t
実際やってみると、Kanjiのツイートはそれ程多くないものだ。時間帯によるのか?
次のステップは、選び出した漢字のツイートを日本語形態素解析に掛けることになる ⇒ [[ノート/テキストマイニング/twitter-2]]
ページ名: