# 文字列の基本 ================ ## 文字列の結合はplus演算子にて可能 ``` >>> "a" + "b" 'ab' ``` ## 数値はstrを使う必要がある。 ``` >>> "a" + 1 Traceback (most recent call last): File "", line 1, in TypeError: cannot concatenate 'str' and 'int' objects >>> "a" + str(1) 'a1' ``` 逆に、文字列を数値として使いたかったらintを使う ``` >>> 1 + "1" Traceback (most recent call last): File "", line 1, in 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 "", line 1, in 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!' ``` [このサンプル](https://github.com/recuraki/PythonJunkTest/blob/master/strings/counter_parse_1.py)