Python文字列操作
Pythonにおける基本的な文字列操作 連結には+演算子を使う a = 'Python' b = '2.7' c = a + b print c # => 'Python2.7' a = 'Python' b = ' is ' c = 'fancy' print a + b + c # => 'Python is fancy' joinメソッドとリスト/タプルを使って連結するテクニック RubyのjoinはArrayのメソッド(連結文字列を引数にとる)、 Pythonのjoinはstrのメソッド(list/tupleを引数にとる)と、逆になっているのでRubyとは異なる strings = ['dog', 'cat', 'penguin'] print ','.join(strings) #=> 'dog,cat,penguin' 繰り返し 同じ内容を繰り返す場合は*演算子で整数を与えると指定した回数だけリピートした文字列が生成されます。 s = 'dog?' print s * 3 #=> 'dog?dog?dog?' 値の埋め込み 文字列に変数の値を展開する際 sprintfスタイル: '%s, %s' % ('Hello', 'World') 拡張sprintfスタイル: '%(a)s, %(b)s' % dict(a='Hello', b='World') formatメソッド利用: '{0}, {1}'.format('Hello', 'World') sprintfスタイル 文字列に % 演算子で値またはlist/tupleを与える a = 'Python' b = 'a programming language' print '%s is %s' % (a, b) # => 'Python is a programming language' c = 'World' print 'Hello, %s!' % c # => 'Hello, World!' 文字列中の展開記号(%sなど)の個数の数だけ、与える値も必要です。 展開記号が1つの場合は%のあとの値はlist/tupleにする必要はありません。 (1要素のlist/tupleでも展開されます) 上の例だと最初のprint文のテンプレート文字列は展開記号%sを2つ含むので、 %の後にくる値で与えるタプルの要素の数も2つになっています。テンプレート文字列中で、%という文字自体を文字として残したい場合は%%と '%'2文字にするとよい です。 以下のようなフォーマット指定子があります。 %s - 文字列として展開 %d - 整数として展開 %f - 小数点数として展開 タプルやリストを '(1, 2, 3)' のような文字列として展開してほしいときは tuple_var = (1, 2, 3) print 'tuple_var is: %s' % (tuple_var,) としないと3個あるのに置換先のプレースホルダが1個しかないのでエラーに フォーマット文字列の%のあとに丸カッコでかこってdictオブジェクトのキーを指定し、 フォーマット文字列に対して%演算子の右辺にdictオブジェクトを指定します。 繰り返し同じ値を埋め込む際、すでにdict変数がある場合などに便利でしょう。 v = dict(first='Michael', family='Jackson') print 'He is %(first)s, %(first)s %(family)s.' % v formatメソッドの利用 formatメソッドを使うことでformatメソッド専用のテンプレート言語を使うことができます。 print '{0}, {1}'.format('Hello', 'World') #=> 'Hello, World' 置換(replace) s = 'Today is Monday.' print s.replace('Monday', 'Sunday') #=> 'Today is Sunday.' s2 = 'Hello Hello' print s.replace('Hello', 'Bye') #=> 'Bye Bye' 第三引数を指定しなければすべて置換 s3 = 'World World' print s.replace('World', 'Hello', 1) #=> 'Hello World' # 第三匹数で置換する個数を指定 あるパターンに従って文字列を置換する、といった処理はre(正規表現)パッケージのsubメソッドを使います。 import re s = 'Hello World' print re.sub(r"[a-z]", "A", s) #=> 'HAAAA WAAAA' N文字目の文字の取得 s = 'abc' n = 1 # 'a'がほしい print s[n-1] # 0ベースインデックスで文字を取得 s2 = 'xyz' print s[-1] # 'z' 最後の文字 部分文字列の取得(N文字目から、M文字とりだす) s = "This is a pen." n = 1 m = 4 print s[n-1:n-1+m] # 'This' print s[0:4] # 'This' print s[-4:-1] # 'pen' 検索 findを使います。後ろ向きに検索したいときはrfindが使えます。 findは該当文字列が見つかれば0からはじまる文字列位置を, 見つからなければ-1を返します。 s = 'abcabcabc' index = s.find('b') # indexは1(2文字目) 第二引数で検索を開始する位置を指定できます。 s = 'abcabcabc' index = s.find('b', 2) # indexは4(5文字目) 以下のようなコードで文字列中からすべてのターゲットを探し出せます。 s = 'abcabcabc' target = 'b' index = -1 while True: index = s.find(target, index + 1) if index == -1: break print 'start=%d' % index 1文字ずつ処理 string型はイテレータでもあるので、以下のようにforで処理できます。文字のlistが欲しければlist(strvalue) for c in 'aiueo': print c print list('hoge') # => ['h', 'o', 'g', 'e'] s = 'aiueo' for i in range(len(s)): c = s[i] print c 両端の空白削除 strip, lstrip, rstripが使えます。 stripは両端からスペース・タブ文字・改行(\rおよび\n)を削除した文字列を、 lstripはstripと同等の処理を左端のみに適用したものを、 rstripはstripと同等の処理を右端のみに適用したものを返します。 s = ' x ' print 'A' + s.strip() + 'B' # => 'AxB' print 'A' + s.lstrip() + 'B' # => 'Ax B' print 'A' + s.rstrip() + 'B' # => 'A xB' 改行削除(perlやrubyのchomp相当の処理) line = 'hoge\n' msg = line.rstrip() + 'moge' print msg # => 'hogemoge' with open('./test.txt') as fh: for line in fh: no_line_break_line = line.rstrip() # なにかする 全部大文字にする upper()メソッドを使います。 print 'hello'.upper() # => 'HELLO' 全部小文字にする lower()メソッドを使います。 print 'BIG'.lower() # => 'big' ある文字列が部分文字列として含まれるかどうか調べる s = 'abc' print 'b' in s #=> True print 'x' in s #=> False ある文字列が部分文字列として登場する回数を数える 先ほど出てきたfindメソッドを使って自力でやってもよいですが、countという便利なメソッドがあります。 s = 'aaabbc' print s.count('b') #=> 2 intを文字列に変換する v = 1 print str(v) print '%d' % v floatを文字列に変換する f = 1.234 print str(f) #=> '1.234' print '%f' % f #=> '1.234000' listを文字列に変換する, tupleを文字列に変換する 変換というか、デバッグprintなどで文字列で表現したいことはありますよね。 v = [1,2,3] print str(v) #=> '[1, 2, 3]' print '%s' % v #=> '[1, 2, 3]' tuple1つを%sで表示しようとすると, Pythonが与えられたtupleをテンプレート用の値のリストと解釈してエラーになってしまいます。 v = (1, 2, 3) print str(v) #=> '(1, 2, 3)' よい例 print '%s' % v #=> '(1, 2, 3)'を期待するが、TypeErrorになってしまう print '%s' % (v,) #=> '(1, 2, 3)' よい例 joinなどを使って組み立ててみるのもいいですね。 v = [1,2,3] print '<' + ('/'.join([ str(item) for item in v ])) + '>' #=> '<1/2/3>' tupleオブジェクトも同様です。 dictを文字列に変換する 変換というか、デバッグprintなどで文字列で表現したい時 v = dict(a=1, b=2) print str(v) #=> "{'a': 1, 'b': 2}" print '%s' % v #=> "{'a': 1, 'b': 2}" keysやリスト内包表記、joinを使ってワンライナーで文字列生成 v = dict(a=1, b=2) print '<' + ', '.join([ '%s=%s' % (k, v[k]) for k in v.keys() ]) + '>' #=> '' (2系) バイト列をunicode文字列にする ファイルやソケットから読み込んだデータはそのままだとバイト列なので、unicode文字列に解釈してあげないと 文字単位の操作がうまくできません。Python2系(2.7など)ではstr(バイト列)とunicode(文字列)は区別されており、 Webアプリケーショなど入力にマルチバイト文字が想定されるシーンでは文字列はunicodeオブジェクトとして扱ったほうがよい。 バイト列をエンコーディングを指定してunicode文字列として解釈するためにはdecodeメソッドを使います。 with open('utf8_content_file.txt', 'rb') as fh: byte_content = fh.read() # ぜんぶ読み込む, この時点ではバイト列 print len(byte_content) # バイト数 unicode_string = byte_content.decode('utf-8') # utf-8エンコーディングで、文字の並びとして解釈 print len(unicode_string) # 文字数 (2系) unicode文字列をバイト列にする 逆にファイルやソケットに書き込むとき、文字列をバイト列にしないといけないです。そういうときはunicodeオブジェクトのencodeメソッドをつかいます。 unicode_string = u'マルチバイト文字の文字列' with open('./utf8_content_file.txt', 'wb') as fh: # 書き込みモードでopen byte_content = unicode_string.encode('utf-8') # utf-8エンコーディングで表現した場合のバイト列を取得 fh.write(byte_content) # バイト列を書き込み