メモ代わり。てきとーに。 いや、ですからてきとーですって。 2年前ぐらいにPythonあたりでメールくれた方、ごめんなさい。メール紛失してしまい無視した形になってしまいました。。。

2008年1月26日土曜日

[Python][お勉強] Python入門(6) - 文字列を理解する

最終目標

Pythonにおける文字列を理解する。

文字列

見ていくものは以下のとおり。

  1. 文字列リテラル
  2. エスケープシーケンス
  3. raw文字列
  4. トリプルクォーテーション
  5. Unicode文字列
  6. 基本的な演算子
  7. インデクシング
  8. スライシング
  9. 型の変換
  10. 文字列の変更
  11. 文字列フォーマット
  12. 文字列のメソッド

・・・結構ボリュームあり。

まず、文字列もオブジェクト

Pythonも文字列はひとつのオブジェクトとして扱う。
文字列はimmutableであるオブジェクトのひとつ。
文字列は「シーケンス」と呼ばれるオブジェクトの一種だそうで。



文字列リテラル

Pythonでは文字列を記述する方法がいくつかある。その方法を以下に記す。

1) シングルクォーテーション


$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'こんちは'
'\xe3\x81\x93\xe3\x82\x93\xe3\x81\xa1\xe3\x81\xaf'
>>> 'abc123'
'abc123'
>>>



日本語はバケバケだけど、こういうもの???
まぁいいや。後で調べるとして次いこう。


2) ダブルクォーテーション


$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> "だぶるくぉーてーしょんだよ"
'\xe3\x81\xa0\xe3\x81\xb6\xe3\x82\x8b\xe3\x81\x8f\xe3\x81\x89\xe3\x83\xbc\xe3\x81\xa6\xe3\x83\xbc\xe3\x81\x97\xe3\x82\x87\xe3\x82\x93\xe3\x81\xa0\xe3\x82\x88'
>>> "Hello,World"
'Hello,World'
>>>



ここで気になるところは、インタラクティブ環境では文字列の出力はシングルクォーテーションで
行われているということ。内部的にはシングルクォーテーションで保持しているということかもしれない。
また、Pythonではシングルクォーテーションとダブルクォーテーションは同じ扱いだそうで。
シングルクォーテーションや、ダブルクォーテーションを文字列の中に入れるときに便利。

例)

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> "O'reilly"
"O'reilly"
>>> '"hello"'
'"hello"'
>>>



3) トリプルクォーテーション


$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> """あいうえお
... かきくけこ
... さしすせそ
... たちつてと"""
'\xa4\xa2\xa4\xa4\xa4\xa6\xa4\xa8\xa4\xaa\n\xa4\xab\xa4\xad\xa4\xaf\xa4\xb1\xa4\xb3\n\xa4\xb5\xa4\xb7\xa4\xb9\xa4\xbb\xa4\xbd\n\xa4\xbf\xa4\xc1\xa4\xc4\xa4\xc6\xa4\xc8'
>>> """GET / HTTP/1.0
... User-Agent: HOGEHOGE
... Host: www.google.com
... """
'GET / HTTP/1.0\nUser-Agent: HOGEHOGE\nHost: www.google.com\n'
>>>




変なクォーテーションだが、複数行からなる文字列を生成するときに便利。
この複数行からなる文字列を「ブロック文字列」と呼ぶらしい。


4) エスケープシーケンス

'\n'とか'\t'とか。

5) raw文字列

ファイルパスなんかを書くときに便利。

例)

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print r"C:\a\b\c"
C:\a\b\c
>>>



といった感じに書ける。raw文字列を使うとエスケープシーケンスが完全に無効になる。


6) Unicode文字列



>>> u'eggs\u0020spam'
u'eggs spam'
>>>



上記はスペースをUnicodeで記述した例。本によるとあんまり使用する機会が無いとのこと。



エスケープシーケンス

文字列の中にバイトコードを埋め込む場合に使用する。
たとえば、改行コード、タブコードを入れる場合など。


>>> print "abcdefg\naaaaaa\nbbbbbb\tccccc"
abcdefg
aaaaaa
bbbbbb ccccc
>>>



などなど。

で、エスケープシーケンスの一覧。
エスケープシーケンス意味
\改行行の継続
\\バックスラッシュ文字
\'シングルクォーテーション文字
\"ダブルクォーテーション文字
\aビープ音を鳴らす
\bバックスペース
\f改ページ
\n改行
\r復帰
\t水平タブ
\v垂直タブ
\N{id}Unicodeデータベース中でidに対応する文字
\uhhhh16ビット16進数値hhhhに対応するUnicode文字
\Uhhhh...32ビット16進数値hhhh...に対応するUnicode文字
\xhh16進数hhに対応するASCII文字
\ooo8進数oooに対応するASCII文字
\0NULL
\その他の文字エスケープシーケンスとしては扱われない






文字列の演算子

文字列を利用する演算子を列挙する。
演算子説明
=代入する
+連結
*繰り返し
s[i]インデクシング
s[i:j]スライシング
len(s)長さを取得する
%文字列フォーマット
.メソッド呼び出し
for x in sループ
'm' in s特定の文字が含まれているかの確認



代入は良いとして、+は連結に使われる。*はPerlで言うところのx演算子か。


>>> 'a' + 'b' # ←連結
'ab'
>>> 'a' * 100 # ←繰り返し
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
>>> print 'あへ' * 10
あへあへあへあへあへあへあへあへあへあへ
>>>

ここまではだいたいわかった。
次は、in演算子。for文で使用する場合とfor文以外で使用する場合の2通りの使い方があるようだ。

for文で使う場合は、、

>>> myjob = "abcdefg"
>>> for c in myjob: print c
...
a
b
c
d
e
f
g



のように使うらしい。for文に使う場合は文字ひとつひとつを取り出す、というイメージ。
もうひとつが、

>>> "k" in myjob
False
>>> "c" in myjob
True
>>>



と、myjob変数の中の文字列に"k"という文字や"c"という文字が含まれているかどうかを
検査する演算子。見つかった場合は、Trule/Falseを返す。


インデクシング

Cで言うところの配列のようなもの。

>>> s = "abcdefg"
>>> s[0]
'a'
>>> s[1]
'b'
>>> s[2]
'c'
>>> s[3]
'd'
>>> s[4]
'e'
>>> s[5]
'f'
>>> s[6]
'g'
>>> s[7]
Traceback (most recent call last):
File "", line 1, in ?
IndexError: string index out of range
>>>



な感じ。存在しない場合は上記のようにエラーになる。
気をつけなきゃいけないのは、Cと違って各要素に値を代入できないこと。

だから、代入しようとすると・・・

>>> s[0] = 'z'
Traceback (most recent call last):
File "", line 1, in ?
TypeError: object does not support item assignment
>>>



と怒られる。
もし、0番目の値を変えたいとするならば、スライシングを使ったりして文字列を再構築する。

あと、添え字に負の数が指定できる。

>>> s = "abcdefg"
>>> s[-1]
'g'
>>> s[-2]
'f'
>>> s[-3]
'e'
>>> s[-4]
'd'
>>> s[-5]
'c'
>>> s[-6]
'b'
>>> s[-7]
'a'
>>>



負の数を指定すると、文字列の最後から添え字が数えられる。
s[-1]と指定した場合はsの最後から一番目の文字、
ということになる。


スライシング

:(コロン)をして抽出文字列の開始位置と終了位置を指定できる。

Syntax
変数名[開始位置:終了位置]


となる。
で、その例。


>>> s = "abcdefg"
>>> s[3:5]
'de'
>>>



「文字列"abcdefg"の最初から3番目の文字から4番目の文字までを抽出せよ」
という意味になる。
終了位置は「含まれない」ので注意が必要。

また、

>>> s = "abcdefg"
>>> s[3:]
'defg'
>>> s[:3]
'abc'
>>>


のように、開始位置、終了位置は省略できる。省略した場合は「残り全部」という意味。
両方とも省略することができる。その場合には文字列「全部」という意味になる。


>>> s = "abcdefg"
>>> s[:]
'abcdefg'
>>>


はたして、両方とも省略するパターンは使用することがあるのかはわからない。。。

スライシングはさらに3つめの添え字も指定できる。
そのときのsyntaxは、

変数名[開始位置:終了位置:いくつおきか]

といった感じ。

3つめの添え字は「シーケンス中の項目をいくつおきに抽出するか」を指定するもの。
といわれてもよくわからないので、実際にやってみよう。

>>> s = "abcdefghijklmnopqrstuvwxyz"
>>> s[0:26:1]
'abcdefghijklmnopqrstuvwxyz'
>>> s[0:26:2]
'acegikmoqsuwy'
>>> s[0:26:3]
'adgjmpsvy'
>>> s[0:26:4]
'aeimquy'
>>> s[0:26:5]
'afkpuz'
>>> s[0:26:6]
'agmsy'
>>> s[0:26:7]
'ahov'
>>> s[0:26:8]
'aiqy'
>>> s[0:26:9]
'ajs'
>>> s[0:26:10]
'aku'
>>> s[0:26:11]
'alw'
>>> s[0:26:12]
'amy'
>>> s[0:26:13]
'an'
>>> s[0:26:14]
'ao'
>>>


なるほど。だいたいわかった。



文字列←→数値変換

int演算子やstr演算子を使うらしい。


>>> a = "123"
>>> int(a) + 1
124
>>> a + str(1)
'1231'
>>>



な感じ。


さて、次は文字列の変更をやってみる。

文字列の変更

たとえば、"abcdefg"という文字列があったとしよう。
この文字列を"aaadefg"という文字列に変更したいとする。

C言語でやった場合は、

char tmp[] = "abcdefg";
tmp[1] = 'a';
tmp[2] = 'a';


とすればよかったものの、Pythonではそうではない。なぜならばPythonでは文字列はimmutableオブジェクトだからである。
では、Pythonで同様のことをするにはどうするか。

まずは同様に操作してみよう。

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> s = "abcdefg"
>>> s[1] = "a"
Traceback (most recent call last):
File "", line 1, in ?
TypeError: object does not support item assignment
>>>

ごらんのとおり、エラーとなってしまう。

正しくは以下のように行う。

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> s = "abcdefg"
>>> s = "aaa" + s[3:]
>>> s
'aaadefg'
>>>

つまり変数sの要素の値を変えるのではなく、変数sを新たに生成する方法をとらなければ
ならない。


さて、次は便利な文字列フォーマットを見ていこう。
文字列フォーマット
Pythonにおける文字列フォーマットは、Cで言うところのsprintfにた役割を果たす。
まずはSyntax。

フォーマット % フォーマットに埋めるオブジェクト(2要素以上であればタプルを使用)


余りを算出する%演算子を使用する。
文字列に対して用いられるとオーバーロードされた演算子%が使用され、
フォーマットとして働く。

では実際の例を見ていこう。

>>> "1 + 1 = %d" % 2
'1 + 1 = 2'
>>>

文字列の中に%dという文字列が存在するが、この値が%演算子以降に書かれている2という
値に置き換わっている。

次は複数要素指定した場合。

>>> "hello, %s 1 + 2 = %d" % ("world", 3)
'hello, world 1 + 2 = 3'
>>>


フォーマットの中に%sと%dの二つが使用されている。
この場合%演算子の後ろにはタプルを用いて指定する。
タプルがいきなり出てきて意味不明だが、とりあえずlistのようなものと思っておく。

以下に文字列フォーマットに使用するコード(%dのようなもの)に何を使用できるか
を一覧にしておく。
コード対応する型
%s文字列
%r文字列(row文字列版)
%c文字
%d10進数
%i整数
%u符号なし整数
%o8進整数
%x16進整数
%X16進整数(A~Fが大文字で出力される)
%e浮動小数点数(指数表記)
%E浮動小数点数(指数表記、eが大文字で出力される)
%f浮動小数点数(10進表記)
%g浮動小数点数(e、f両方の機能を持つ)
%G浮動小数点数(E,f両方の機能を持つ)
%%%文字


さらに細かく指定できる。そのときのSyntaxは以下のとおり。

%[(キー)][フラグ][桁数][.精度]コード


いきなりキーと言われてもいまいちピンとこないと思うので実際の例を以下に。

>>> aval = "abc"
>>> bval = "def"
>>> cval = "ghi"
>>> "%(cval)s %(bval)s %(aval)s" % vars()
'ghi def abc'
>>>


キーというのは、上記で言う()で囲まれた値。cvalとかbvalとか。
これを理解するためにはvars()関数を理解しなければいけない。
vars()関数は、そのコールされた時点で定義されている変数を
ディクショナリにして返してくれる。

だから、

>>> a = "10"
>>> b = "20"
>>> c = "30"
>>> vars()
{'a': '10', 'c': '30', 'b': '20', '__builtins__': , '__name__': '__main__', '__doc__': None}
>>>

のようになる。
a、b、cのほかに__builtins__とかあるが、ここでは無視しておく。
で、上記のキーというのはディクショナリのキーのこと。
だから先ほどの例で、cvalと指定したところにはcvalの値が展開されている。

フラグというのは、+、-、0のことでCと一緒。
+は右よせ、-は左よせ。0は0埋めせよということ。
桁数と精度もCと一緒っぽい。


最後に文字列のメソッドを見ていく。


文字列メソッド


文字列はそれ自身オブジェクトであるので、そのメソッドをコールできる。

文字列のメソッドはたくさんあるので、とりあえずいくつか代表的なものだけ見ていく。

まず下を見てもらいたい。

>>> s = 'xxxxSPAMxxxxSMAPxxxx'
>>> where = s.find('SPAM')
>>> where
4
>>>


s変数は文字列オブジェクトである。sオブジェクトのfindメソッドを呼んでみた例である。
文字列の中にSPAMという文字列がある位置を返している。上記の例では4と返されている。
これはSPAMという文字列の開始インデックスをあらわしている。

上記の値を使用して置換をすると以下のようになる。

>>> s = s[:where] + 'EGGS' + s[(where + 4):]
>>> s
'xxxxEGGSxxxxSMAPxxxx'



もっと簡単に行うにはreplaceメソッドを使えばよい。


>>> s = 'xxxxSPAMxxxxSPAMxxxx'
>>> s.replace('SPAM','EGGS')
'xxxxEGGSxxxxEGGSxxxx'
>>>

簡単に言うと、s/SPAM/EGGS/gという感じ。
gフラグをつけない置換をしたい場合は、

>>> s = 'xxxxSPAMxxxxSPAMxxxx'
>>> s.replace('SPAM','EGGS',1)
'xxxxEGGSxxxxSPAMxxxx'
>>>

とreplaceメソッドの最後の引数に1を指定する必要がある。

文字列オブジェクトは値を変更できないので別の直接変更できるオブジェクトに変換した方が良い場合がある。

>>> S = 'spammy'
>>> L = list(S)
>>> L
['s', 'p', 'a', 'm', 'm', 'y']

上記は、文字列’spammy'を直接変更できるオブジェクトのlistに変換した例。
listに変換しておけばそれぞれの要素を直接編集できる。


>>> L[3] = 'x'
>>> L[4] = 'x'
>>> L
['s', 'p', 'a', 'x', 'x', 'y']



再度listから文字列に戻すには、文字列オブジェクトのメソッドjoinを使用すれば良い。


>>> S = ''.join(L)
>>> S
'spaxxy'
>>>



CのstrtokやPerlのsplitのように文字列を分解するには、splitメソッドを使用する。

>>> line = 'aaa bbb cccc'
>>> cols = line.split()
>>> cols
['aaa', 'bbb', 'cccc']
>>>


とスペースをデリミタとしてトークンに分解できる。結果はリストで返される。
デリミタを指定するにはsplitメソッドの引数として渡してやれば良い。


>>> line = 'aaa,bbb,cccc'
>>> cols = line.split(',')
>>> cols
['aaa', 'bbb', 'cccc']


まとめ

文字列について学んだ。
学んだこと・注意すべき点は以下のとおり。
  • 文字列はimmutableである。
  • 直接操作したい場合は別の型に変換するか、再生成する。
  • オブジェクトなのでメソッドが使用できる。
  • replaceはデフォルトでは全置換。置換数を指定することもできる。
  • フォーマットはCとほぼ一緒な感じで使用できる。キーだけは特殊。
  • Cには無いraw文字列。パスなどを指定する場合に便利。
  • Unicode文字列というのもあり。
  • シングルクォーテーションとダブルクォーテーションは同義。
  • トリプルクォーテーションはブロック文字列を記述するときに便利。
といった感じ。

次はリストについて見ていこうと思う。




0 コメント: