文字列の基本

文字列の結合は+演算子にて可能

>>> "a" + "b"
'ab'

数値はstr()を使う必要がある。

>>> "a" + 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects
>>> "a" + str(1)
'a1'

逆に、文字列を数値として使いたかったらintを使う

>>> 1 + "1"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>> 1 + int("1")
2

文字列は「文字の配列」として扱える。 また、また、基本的な配列の使い方についておさらいする。

>>>
# 0 = 1文字目
>>> "abcdef"[0]
'a'
# 3文字目以降を表示
>>> "abcdef"[3:]
'def'
# 3文字目までを表示
>>> "abcdef"[:3]
'abc'
# -1文字目までを表示 = 最大より1文字少ない
>>> "abcdef"[:-1]
'abcde'
# 2 から 4より前の文字を表示
>>> "abcdef"[2:4]
'cd'

とても簡単な文字列比較の例

>>> "abc"[0] == "a"
True
>>> "ABC"[0] == "a"
False

文字列操作

検索

>>> "this is a pen".find("pen")
10
>>> "this is a pen".find("cup")
-1
# なので、含まれているかの比較は以下のようにする
if string.find("cup") != -1:
  (-1 = 含まれていない「ではない」時の処理)

置き換え

>>> "abc".replace("a", "b")
'bbc'
# 文字列も置き換えられる
>>> "abc".replace("ab", "xx")
'xxc'

高度な検索や置換の為に: 正規表現

はじめに

正規表現は「パターン」を表します。 基本的な使い方を示します。

まずは、柔軟な検索の例として見ます。 ただし、検索だけでは正規表現の「おいしさ」は分かりませんので、 まずは例を実行した後、更に深く進めてください。

パターンの例

ここはあとでかくこと

検索

>>>
# xyという文字列を探します
>>> re.search("xy", "abcxyz")
<_sre.SRE_Match object at 0x108714cc8>
# aの後に「なにか2文字」あってxを探します
>>> re.search("a..x", "abcxyz")
<_sre.SRE_Match object at 0x108714d30>
# aの後に「なにかが0文字以上」あってyzと続く文字列
>>> re.search("a.*yz", "abcxyz")
<_sre.SRE_Match object at 0x108714cc8>
# aのあとに「bが1文字以上」あるもの
>>> re.search("ab+", "aaaabbccc")
<_sre.SRE_Match object at 0x108714d30>
# なので、以下の例はひっかかりません
>>> re.search("ab+", "aaaaccc")
# でも、以下はaのあとにbが0文字以上なので引っかかります
>>> re.search("ab*", "aaaaccc")
<_sre.SRE_Match object at 0x108714d30>

なにがひっかかったのか?

groupという関数を利用します

>>>
# aのあとに任意の文字列があってyで終わるものを探す
>>> re.search("a.*y", "abcxyz")
<_sre.SRE_Match object at 0x108714d30>
# なにが引っかかった?
>>> re.search("a.*y", "abcxyz").group()
'abcxy'

でも、結果がNoneの場合はgroupはないので気をつけてください。

>>>
# 以下の文字列は引っかからないので、groupという関数がない
>>> re.search("a.*d", "abcxyz").group()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'

文字列の繰り返し

>>>
# 以下はabcを探します
>>> re.search("abc", "abcabcabc").group()
'abc'
# 「abc」が*=0個以上続いている文字とマッチします
>>> re.search("(abc)*", "abcabcabc").group()
'abcabcabc'
# *ではなく、{}で個数の指定も可能です
>>> re.search("(abc){1,2}", "abcabcabc").group()
'abcabc'
# helのあとにloが1-2個続いているものとマッチします
>>> re.search("hel(lo){1,2}", "hellolololo").group()
'hellolo'

文字列単位でのOR

>>>
>>> re.search("(apple|orange)", "I have a pen.")
>>> re.search("(pen|orange)", "I have a pen.").group()
'pen'
>>> re.search("(pen|orange)+", "I have a penpenpen.").group()
'penpenpen'

賢い検索

大切なのは「パターン」という認識です。 例えば、incounter: 200という結果があったとします。 このとき、200だけを抜き出したいとします。

以下のように考えます。 “incounter”という文字列がある そのあとに”:”があって、” “がある。 そのあと、「数字が適当な数ある」

正規表現を学んだので、以上は”incounter: [0-9]+”や、 “incounter: d+”と表せることが分かっています。 ここの[0-9]+やd+の部分が欲しい訳です。

>>> re.match("incounter: (\d+)", "incounter: 100").group(1)
'100'

“d+”の左右にある「()」がポイントです。これが「パターン」を意味します。 つまり、「数字が1個以上あるパターン」をmatch(するか確認)した訳です。 これを、groupで取り出します。 この中の(1)は「1個目のパターン」という意味です。

「1個目の」と言ったのは意味があります。例えば、 “incounter: 100, outcounter: 200”という文字列があります。

>>> re.match("incounter: (\d+), outcounter: (\d+)", "incounter: 100, outcounter: 200").group(1)
'100'
>>> re.match("incounter: (\d+), outcounter: (\d+)", "incounter: 100, outcounter: 200").group(2)
'200'
# groupsで全てをタプルの形で得ることもできます
>>> re.match("incounter: (\d+), outcounter: (\d+)", "incounter: 100, outcounter: 200").groups()
('100', '200')

置換

subで「置き換え」ができます。 何に使うのかは分かりませんが、 “nで始まり:で終わる文字列”を空白に置き換えます。

>>> re.sub("n.*:", "", "incount: 100")
'i 100'

つぎは、「賢い置換」をします。 “\n”というnで、「n個目のパターン」という参照が可能です。

>>> re.sub("incounter: (\d+)", "IN is \\1!", "incounter: 100")
'IN is 100!'

このサンプル