6章学習記録 » 履歴 » バージョン 1
Tatsuya ISHIGAKI, 2025/06/30 13:11
| 1 | 1 | Tatsuya ISHIGAKI | # 第6章 テキストの処理 |
|---|---|---|---|
| 2 | |||
| 3 | ## 6.1 一般的な文字列操作を行う str, string |
||
| 4 | |||
| 5 | - 文字列リテラル |
||
| 6 | - シングルクォート、ダブルクォート |
||
| 7 | - 文字列定義は1行で行う (開始クォートと終了クォートの間に、ソースコードの改行を行うとエラー) |
||
| 8 | - 表現される文字列に改行を入れる場合はエスケープシーケンス `\n` |
||
| 9 | - シングルクォート、ダブルクォートに差は無い |
||
| 10 | - 終了クォートが異なるので、文字列中に他方のクォートを使用したい場合等で使い分ける |
||
| 11 | - (例) `"I'm a champion"` `'say "HELLO", please'` |
||
| 12 | ```python |
||
| 13 | >>> s = "aaa\nbbbb\nccccc" |
||
| 14 | >>> print(s) |
||
| 15 | aaa |
||
| 16 | bbbb |
||
| 17 | ccccc |
||
| 18 | >>> s |
||
| 19 | 'aaa\nbbbb\nccccc' # 実際にはこのように保持されている |
||
| 20 | ``` |
||
| 21 | - 3つのシングルクォート、3つのダブルクォート |
||
| 22 | - 文字列定義が複数行にわたっても良い (開始クォートと終了クォートの間にソースコードの改行を行うと、そこは文字列でも改行扱い) |
||
| 23 | - エスケープシーケンス `\n` を使っても改行される |
||
| 24 | ```python |
||
| 25 | >>> s2 = """AAA\nBBB |
||
| 26 | ... BBB |
||
| 27 | ... CCC\n\nDDD""" |
||
| 28 | >>> print(s2) |
||
| 29 | AAA |
||
| 30 | BBB |
||
| 31 | BBB |
||
| 32 | CCC |
||
| 33 | |||
| 34 | DDD |
||
| 35 | >>> s2 |
||
| 36 | 'AAA\nBBB\nBBB\nCCC\n\nDDD' # 実際にはこのように保持されている |
||
| 37 | ``` |
||
| 38 | - raw文字列 |
||
| 39 | - クォート前に **r** を付ける `r"How are you ?\nI'm fine."` |
||
| 40 | - エスケープシーケンスが無視され、書いた通りに保持される |
||
| 41 | ```python |
||
| 42 | >>> s3 = r"AAA\nBBB" |
||
| 43 | >>> print(s3) |
||
| 44 | AAA\nBBB |
||
| 45 | >>> s3 |
||
| 46 | 'AAA\\nBBB' # 実際にはこのように保持されている (\ が \\ に置換されている) |
||
| 47 | ``` |
||
| 48 | - 文字列リテラルの接続 |
||
| 49 | - 文字列リテラルをスペースでつなげると、接続された単一文字列扱い |
||
| 50 | ```python |
||
| 51 | >>> s4 = "AAA" "bbb" "CCC" |
||
| 52 | >>> s4 |
||
| 53 | 'AAAbbbCCC' |
||
| 54 | ``` |
||
| 55 | - `()` で囲んで、文字列リテラルを複数行に分けて書くと、接続された単一文字列扱い |
||
| 56 | - **注意** カンマを書くとタプル扱いとなってしまう |
||
| 57 | ```python |
||
| 58 | >>> s5 = ( |
||
| 59 | ... "[1]This is" |
||
| 60 | ... "[2]other" |
||
| 61 | ... "[3]lines string literal" |
||
| 62 | ... ) |
||
| 63 | >>> s5 |
||
| 64 | '[1]This is[2]other[3]lines string literal' |
||
| 65 | ``` |
||
| 66 | ```python |
||
| 67 | >>> s6 = ( |
||
| 68 | ... "string1", |
||
| 69 | ... "string2" |
||
| 70 | ... ) |
||
| 71 | >>> s6 |
||
| 72 | ('string1', 'string2') # タプル |
||
| 73 | ``` |
||
| 74 | - 文字列以外のオブジェクトを文字列へ変換 |
||
| 75 | - 関数 `str()` へオブジェクトを渡すことで文字列を取得する |
||
| 76 | - この際に取得される文字列は、オブジェクトの特殊メソッド `__str__()` の値 |
||
| 77 | - 文字列のチェックメソッド (str オブジェクトのチェック用メソッド) |
||
| 78 | |メソッド名|解説| |
||
| 79 | |---|---| |
||
| 80 | |isalnum() |数字と文字| |
||
| 81 | |isalpha() |文字のみ| |
||
| 82 | |isdecimal() |10進数字| |
||
| 83 | |isdigit() |数字を表す文字| |
||
| 84 | |isidentifier()|識別子として使用できる| |
||
| 85 | |islower() |小文字| |
||
| 86 | |isnumeric() |数を表す文字列 (漢数字なども含む)| |
||
| 87 | |isprintable() |印字可能| |
||
| 88 | |isspace() |スペース、タブなどの空白文字| |
||
| 89 | |istitle() |単語の先頭のみ大文字であとは小文字| |
||
| 90 | |isupper() |大文字| |
||
| 91 | |||
| 92 | - 文字列の変換メソッド (str オブジェクトの変換メソッド) |
||
| 93 | |メソッド名|解説| |
||
| 94 | |---|---| |
||
| 95 | |upper()|| |
||
| 96 | |lower()|| |
||
| 97 | |swapcase()|大文字を小文字に、小文字を大文字に| |
||
| 98 | |capitalize()|先頭1文字を大文字に、それ以外を小文字に| |
||
| 99 | |title()|単語毎に大文字1文字 + 小文字に| |
||
| 100 | |replace(old, new[, count])|old を new へ置換<br>(count 指定の場合は、先頭から指定数まで変換)| |
||
| 101 | |strip([chars])|先頭および末尾から、指定した文字列中の **文字** をすべて除去<br>chars 指定なしの場合は空白文字が削除される| |
||
| 102 | |lstrip([chars])|先頭から (同上)| |
||
| 103 | |rstrip([chars])|末尾から (同上)| |
||
| 104 | |zfill(width)|長さが width になるように、左に 0 を詰める| |
||
| 105 | |removeprefix(prefix, /)|先頭から prefix で指定した **文字列** を除去| |
||
| 106 | |removesuffix(suffix, /)|末尾から suffix (同上)| |
||
| 107 | |||
| 108 | - その他文字列メソッド |
||
| 109 | |メソッド名|解説| |
||
| 110 | |---|---| |
||
| 111 | |find(sub[, start[, end]])|sub の出現位置を返す<br>無い場合は -1| |
||
| 112 | |split(sep=None, maxsplit=-1)|sep で分割したリストを返す (デフォルトは空白文字で分割)| |
||
| 113 | |join(iterable)|引数それぞれを文字列で連結した単一文字列を返す| |
||
| 114 | |startswith(prefix[, start[, end]])|prefix を先頭に持つかを判定<br>prefix はタプルで複数候補を指定可能| |
||
| 115 | |endswith(suffix[, start[, end]])|suffix を末尾に持つかを判定<br>suffix はタプルで複数候補を指定可能| |
||
| 116 | |encode(encoding="utf-8", errors="strict")|encoding で指定したエンコード形式に変換する<br>errors は変換できない文字があった場合の対応方法 `strict`:例外発生、`ignore`:対応文字無視、`replace`:対応文字を ? に変換| |
||
| 117 | |||
| 118 | - 文字列定数 |
||
| 119 | |定数名|解説| |
||
| 120 | |---|---| |
||
| 121 | |string.ascii_lowercase|英小文字 `"abcdefghijklmnopqrstuvwxyz"` (以下同様)| |
||
| 122 | |string.ascii_uppercase|英大文字| |
||
| 123 | |string.ascii_letters|英小文字、英大文字| |
||
| 124 | |string.digits|0-9| |
||
| 125 | |string.hexdigit|0-9, a-f, A-F| |
||
| 126 | |string.octdigit|0-7| |
||
| 127 | |string.punctuation|記号| |
||
| 128 | |string.whitespace|空白 (スペース、タブ、改行等)| |
||
| 129 | |string.printable|ascii_letter, digit, punctuation| |
||
| 130 | |||
| 131 | - `in` によるチェック |
||
| 132 | - `部分文字列 in 文字列` により bool が返る |
||
| 133 | ```python |
||
| 134 | >>> value = 'Python' |
||
| 135 | >>> 'P' in value # 文字列に'P'が含まれている |
||
| 136 | True |
||
| 137 | >>> 'yth' in value # 文字列に'yth'が含まれている |
||
| 138 | True |
||
| 139 | >>> 'x' in value # 文字列に'x'が含まれていない |
||
| 140 | False |
||
| 141 | >>> 'xyz' in value # 文字列に'xyz'が含まれていない |
||
| 142 | False |
||
| 143 | >>> 'p' in value # 文字列に'p'は含まれていない(大文字と小文字は区別される) |
||
| 144 | False |
||
| 145 | ``` |
||
| 146 | |||
| 147 | ## 6.2 フォーマットと文字列リテラル f-string |
||
| 148 | - f-string の書き方 |
||
| 149 | - 文字列に `f` または `F` を前置する |
||
| 150 | - f-string 内の `{expression}` は、expression を Python が式として処理した結果となる |
||
| 151 | ```python |
||
| 152 | >>> name = "smith" |
||
| 153 | >>> num = 20 |
||
| 154 | >>> f"{name} has {num} items." |
||
| 155 | 'smith has 20 items.' |
||
| 156 | ``` |
||
| 157 | ```python |
||
| 158 | >>> a = 12 |
||
| 159 | >>> b = 3 |
||
| 160 | >>> f'a + b = {a + b}' |
||
| 161 | 'a + b = 15' |
||
| 162 | >>> f'a / b = {a / b}' |
||
| 163 | 'a / b = 4.0' |
||
| 164 | ``` |
||
| 165 | - `=` を付けた出力 |
||
| 166 | - f-string 中に `{変数名=}` を書くと、その部分は「変数名 = 値」と出力される |
||
| 167 | ```python |
||
| 168 | >>> num = 20 |
||
| 169 | >>> name = "smith" |
||
| 170 | >>> f"{name=}, {num=}" |
||
| 171 | "name='smith', num=20" |
||
| 172 | ``` |
||
| 173 | - フォーマットの指定方法 |
||
| 174 | - f-string でコロンを使ったフォーマット書式を記述することで、出力をフォーマットできる |
||
| 175 | |書式|解説| |
||
| 176 | |---|---| |
||
| 177 | |`:<30` `:>30` `:^30`|指定幅で左寄せ、右寄せ、中央寄せ| |
||
| 178 | |`:-<30` `:->30` `:-^30`|指定幅で左寄せ、右寄せ、中央寄せし、その際にスペースではなく指定文字 (左記例では `-`) を埋める| |
||
| 179 | |`:b` `:o` `:d` `:x` `:X`|2進数、8進数、10進数、16進数(小文字)、16進数(大文字) に変換する| |
||
| 180 | |`:f`|固定小数点の文字列へ変換| |
||
| 181 | |`:%`|百分率表記へ変換| |
||
| 182 | |`:,`|数値3桁ごとにカンマを挿入する| |
||
| 183 | |`:6.2f`|表示桁数指定 (左記例では 6:全体桁数、2:小数点以下桁数)<br>※全体桁数は小数点を含む文字数で、右寄せスペース埋め| |
||
| 184 | |`:%Y-%m-%d` `:%H:%M:%S`|日付型の書式| |
||
| 185 | |||
| 186 | ```python |
||
| 187 | >>> import math |
||
| 188 | >>> value = 'left align' |
||
| 189 | >>> f'|{value:<30}|' # 文字列を左に寄せて、30文字になるようにスペースで埋める |
||
| 190 | '|left align |' |
||
| 191 | >>> value = 'right align' |
||
| 192 | >>> f'|{value:>30}|' # 文字列を右に寄せて、30文字になるようにスペースで埋める |
||
| 193 | '| right align|' |
||
| 194 | >>> value = 'center' |
||
| 195 | >>> f'|{value:^30}|' # 文字列を中央にそろえて、30文字になるようにスペースで埋める |
||
| 196 | '| center |' |
||
| 197 | >>> f'{value:-^30}' # 文字列を中央にそろえて、30文字になるように「-」で埋める |
||
| 198 | '------------center------------' |
||
| 199 | >>> value = 1000 |
||
| 200 | >>> f'{value:b} {value:o} {value:d} {value:x} {value:X}' # 2進数、8進数、10進数、16進数(小文字)、16進数(大文字)に変換 |
||
| 201 | '1111101000 1750 1000 3e8 3E8' |
||
| 202 | >>> f'{math.pi} {math.pi:f}' # 「:f」で固定小数点数の文字列に変換 |
||
| 203 | '3.141592653589793 3.141593' |
||
| 204 | >>> value = 0.045 |
||
| 205 | >>> f'{value:%}' # 百分率での表記に変換 |
||
| 206 | '4.500000%' |
||
| 207 | >>> value = 10000000000000 |
||
| 208 | >>> f'{value:,}' # 数値に3桁ごとにカンマを挿入 |
||
| 209 | '10,000,000,000,000' |
||
| 210 | >>> f'{math.pi:>5.2f}' # 小数点以下が2桁になるよう変換し、文字列を右に寄せて全体が5桁になるようスペースで埋める |
||
| 211 | ' 3.14' |
||
| 212 | >>> value = 0.045 |
||
| 213 | >>> f'{value:>8.2%}' # 小数点以下が2桁の百分率になるよう変換し、文字列を右に寄せて全体が8桁になるようスペースで埋める |
||
| 214 | ' 4.50%' |
||
| 215 | >>> from datetime import datetime |
||
| 216 | >>> now = datetime.now() |
||
| 217 | >>> f'Today is {now:%Y-%m-%d}' # 年月日に変換 |
||
| 218 | 'Today is 2021-06-06' |
||
| 219 | >>> f'Current time is {now:%H:%M:%S}' # 時分秒に変換 |
||
| 220 | 'Current time is 23:01:21' |
||
| 221 | ``` |
||
| 222 | - 小数フォーマット実験 |
||
| 223 | ```python |
||
| 224 | >>> f"{50.1:10.3f}" |
||
| 225 | ' 50.100' # 右寄せ、スペース埋め |
||
| 226 | >>> f"{50.1:2.1f}" |
||
| 227 | '50.1' # 必要桁数は出力される (全体2桁指定でも4桁になる) |
||
| 228 | >>> f"{50.1:2.2f}" |
||
| 229 | '50.10' # 小数点以下桁数が優先されて、全体は必要桁数となる |
||
| 230 | ``` |
||
| 231 | - f-string 導入前のフォーマット方法 |
||
| 232 | - f-string は Python3.6 で導入、その前は `str.format()` メソッドを使用していた |
||
| 233 | ```python |
||
| 234 | # インデックスで指定 |
||
| 235 | >>> name = "smith" |
||
| 236 | >>> num = 20 |
||
| 237 | >>> "{0} has {1} items.".format(name, num) |
||
| 238 | 'smith has 20 items.' |
||
| 239 | >>> "{1} is {1}".format(num, name) |
||
| 240 | 'smith is smith' |
||
| 241 | >>> "{1} has {3} items.".format(name, num) # 引数の位置指定は 0, 1, ... |
||
| 242 | Traceback (most recent call last): |
||
| 243 | File "<python-input-24>", line 1, in <module> |
||
| 244 | "{1} has {3} items.".format(name, num) |
||
| 245 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^ |
||
| 246 | IndexError: Replacement index 3 out of range for positional args tuple |
||
| 247 | ``` |
||
| 248 | ```python |
||
| 249 | >>> name = "smith" |
||
| 250 | >>> num = 20 |
||
| 251 | # 宣言順で指定 |
||
| 252 | >>> "{} has {} items.".format(name, num) |
||
| 253 | 'smith has 20 items.' |
||
| 254 | ``` |
||
| 255 | ```python |
||
| 256 | # キーワードで指定 |
||
| 257 | >>> name = "smith" |
||
| 258 | >>> num = 20 |
||
| 259 | >>> "{first} has {second} items.".format(first=name, second=num) |
||
| 260 | 'smith has 20 items.' |
||
| 261 | ``` |
||
| 262 | - 書式指定も可能 |
||
| 263 | ```python |
||
| 264 | >>> name = "smith" |
||
| 265 | >>> num = 20 |
||
| 266 | >>> "{0:=<10} has {1} items.".format(name, num) |
||
| 267 | 'smith===== has 20 items.' |
||
| 268 | >>> "{} has {:5.2f} items.".format(name, num) |
||
| 269 | 'smith has 20.00 items.' |
||
| 270 | >>> "{first:=^20} has {second} items.".format(first=name, second=num) |
||
| 271 | '=======smith======== has 20 items.' |
||
| 272 | ``` |
||
| 273 | - `%` 演算子 |
||
| 274 | - C言語の printf 第1引数と同様の文字列を使う (代入される位置に `%s` `%d` などを書く) |
||
| 275 | - 前記文字列リテラルの後に `%` に続けて代入する値(式)を記述する (複数の場合はタプルを指定) |
||
| 276 | ```python |
||
| 277 | >>> name = "smith" |
||
| 278 | >>> num = 20 |
||
| 279 | >>> "Hello, %s" % "everybody" |
||
| 280 | 'Hello, everybody' |
||
| 281 | >>> "%s has %d items." % (name, num) |
||
| 282 | 'smith has 20 items.' |
||
| 283 | ``` |
||
| 284 | |||
| 285 | ## 6.3 正規表現を扱う re |
||
| 286 | 正規表現を扱うには `re` モジュールを使う |
||
| 287 | - 関数 search, match |
||
| 288 | - `search(pattern, string, flags=0)` |
||
| 289 | - `pattern` 正規表現文字列 |
||
| 290 | - `string` 正規表現にマッチするか確認する文字列 |
||
| 291 | - `flags` 正規表現コンパイル時の振る舞いを変更するフラグを指定 |
||
| 292 | - 戻り値はマッチオブジェクト (`re.Match` のインスタンス) |
||
| 293 | - `match(pattern, string, flags=0)` |
||
| 294 | - search() と同じだが、文文字の先頭にのみマッチ検査する |
||
| 295 | - ※複数行文字列でも、先頭の一か所のみ |
||
| 296 | ```python |
||
| 297 | >>> import re |
||
| 298 | >>> re.search("m.", "Smismith") |
||
| 299 | <re.Match object; span=(1, 3), match='mi'> # ヒットすると Match オブジェクトが返る |
||
| 300 | >>> re.match("m.", "Smismith") |
||
| 301 | >>> # match では先頭からのみ検索するので、ヒット無しで None が返る |
||
| 302 | ``` |
||
| 303 | - re モジュールのフラグ定数 |
||
| 304 | - 正規表現コンパイル時に指定するフラグ |
||
| 305 | - `re.search()` `re.match()` での `flags` 引数部分に指定するもの |
||
| 306 | - (補足) `re.search()` `re.match()` では、コンパイルと同時に検索が実行されるが、コンパイルした正規表現オブジェクト (`re.compile` のインスタンス) については後述 |
||
| 307 | |定数名|解説| |
||
| 308 | |---|---| |
||
| 309 | |A, ASCII|\w, \s などのマッチングで Unicode ではなく ASCII 文字列のみを使用する| |
||
| 310 | |I, IGNORECASE|大文字小文字を区別せずマッチ| |
||
| 311 | |M, MULTILINE|複数行テキスト指定の際 `^` `$` が各行の先頭と末尾にマッチする| |
||
| 312 | |S, DOTALL|`.` が改行文字も含めてマッチする| |
||
| 313 | |||
| 314 | ```python |
||
| 315 | >>> import re |
||
| 316 | >>> re.search("s..", "Smismith") |
||
| 317 | <re.Match object; span=(3, 6), match='smi'> |
||
| 318 | >>> re.search("s..", "Smismith", re.I) |
||
| 319 | <re.Match object; span=(0, 3), match='Smi'> |
||
| 320 | ``` |
||
| 321 | |||
| 322 | - 正規表現オブジェクト re.Pattern |
||
| 323 | - 正規表現オブジェクトを作成して、そのメソッドでマッチングを行う方法もある |
||
| 324 | 1. 検索対象の文字列を指定せず、正規表現オブジェクトを `re.compile()` によって作成する |
||
| 325 | 1. 正規表現オブジェクトのメソッドで、検索対象の文字列を指定して結果を得る |
||
| 326 | |||
| 327 | |メソッド名|解説|戻り値| |
||
| 328 | |---|---|---| |
||
| 329 | |`search(string[, pos[, endpos]])`|指定した文字列がマッチするかを返す<br>`pos` `endpos` はマッチ処理の対象となる位置を指定|マッチオブジェクト、None| |
||
| 330 | |`match(string[, pos[, endpos]])`|指定文字列の先頭がマッチするかを返す<br>他 `search()` と同様|マッチオブジェクト、None| |
||
| 331 | |`fullmatch(string[, pos[, endpos]])`|指定文字列全体が正規表現にマッチするかを返す|マッチオブジェクト、None| |
||
| 332 | |`split(string, maxsplit=0)`|指定文字列を、正規表現にマッチした文字列で分割する<br>`maxsplit` は分割の最大数|文字列 list| |
||
| 333 | |`sub(repl, string, count=0)`|指定文字列のなかで正規表現にマッチした文字列を repl に置き換える<br>`count` は置換回数上限|str| |
||
| 334 | |`findall(string[, pos[, endpos]])`|指定文字列中で正規表現にマッチした文字列すべてを返す|文字列 list| |
||
| 335 | |`finditer(string[, pos[, endpos]])`|指定文字列中で正規表現にマッチした「マッチオブジェクト」をイテレータで返す|イテレーター (re.Match)| |
||
| 336 | - `search()` の例 |
||
| 337 | ```python |
||
| 338 | >>> import re |
||
| 339 | >>> pattern = re.compile("s..") # 正規表現 "s.." のオブジェクト生成 |
||
| 340 | >>> type(pattern) |
||
| 341 | <class 're.Pattern'> # 正規表現オブジェクトは re.Pattern 型 |
||
| 342 | >>> pattern |
||
| 343 | re.compile('s..') |
||
| 344 | >>> pattern_i = re.compile("s..", re.I) # フラグ付きの 正規表現オブジェクト |
||
| 345 | >>> pattern_i |
||
| 346 | re.compile('s..', re.IGNORECASE) |
||
| 347 | >>> target = "Smismith" |
||
| 348 | >>> pattern.search(target) |
||
| 349 | <re.Match object; span=(3, 6), match='smi'> # re.search() と同じ動作 |
||
| 350 | >>> pattern_i.search(target) |
||
| 351 | <re.Match object; span=(0, 3), match='Smi'> |
||
| 352 | ``` |
||
| 353 | - 他メソッドの例 |
||
| 354 | ```python |
||
| 355 | >>> import re |
||
| 356 | >>> import string |
||
| 357 | >>> pat.fullmatch(string.ascii_lowercase) |
||
| 358 | >>> pat.fullmatch(string.ascii_lowercase, 2, 14) |
||
| 359 | <re.Match object; span=(2, 14), match='cdefghijklmn'> |
||
| 360 | ``` |
||
| 361 | ```python |
||
| 362 | >>> import re |
||
| 363 | >>> pat = re.compile(r"\s+") |
||
| 364 | >>> pat.split("I am Smith. Nice to meet you.") |
||
| 365 | ['I', 'am', 'Smith.', 'Nice', 'to', 'meet', 'you.'] |
||
| 366 | >>> pat.sub(" & ", "I am Smith.") |
||
| 367 | 'I & am & Smith.' |
||
| 368 | ``` |
||
| 369 | ```python |
||
| 370 | >>> import re |
||
| 371 | >>> pat = re.compile(r"\b\d{3}-\d{4}\b") # 郵便番号の形式をイメージ |
||
| 372 | >>> pat.findall("111-0000 22-0000 3333-0000 444-000 555-00000 666-0000 777-9999") |
||
| 373 | ['111-0000', '666-0000', '777-9999'] |
||
| 374 | >>> ite = pat.finditer("111-0000 22-0000 3333-0000 444-000 555-00000 666-0000 777-9999") |
||
| 375 | >>> for postnum in ite: |
||
| 376 | ... print(postnum) |
||
| 377 | ... |
||
| 378 | <re.Match object; span=(0, 8), match='111-0000'> # 取得されているのはマッチオブジェクト |
||
| 379 | <re.Match object; span=(45, 53), match='666-0000'> |
||
| 380 | <re.Match object; span=(54, 62), match='777-9999'> |
||
| 381 | ``` |
||
| 382 | |||
| 383 | - 同じ正規表現でマッチングを繰り返すなら、正規表現オブジェクトを生成して使うべき (ただし、`re.search()` 等でもキャッシュ機能はある) |
||
| 384 | |||
| 385 | - マッチオブジェクト |
||
| 386 | - re モジュールの関数やメソッドで返されるオブジェクト |
||
| 387 | - 正規表現中に `()` で囲んだ部分は「サブグループ」となり、その部分文字列だけを取得できる |
||
| 388 | - マッチオブジェクトからのサブグループ取得方法は以下の2種類 |
||
| 389 | - `group()` メソッド |
||
| 390 | - `[]` でのインデックス指定 |
||
| 391 | ```python |
||
| 392 | >>> import re |
||
| 393 | >>> pat = re.compile(r"(\d\d) ([^ ]+) (\d{4}/\d{2}/\d{2}) (\d{2}:\d{2}:\d{2}) (.+)") |
||
| 394 | >>> pat.match("04 process-001 2025/06/27 12:36:59 START") |
||
| 395 | <re.Match object; span=(0, 40), match='04 process-001 2025/06/27 12:36:59 START'> |
||
| 396 | >>> mobj = pat.match("04 process-001 2025/06/27 12:36:59 START") |
||
| 397 | >>> mobj[0] # インデックス数値指定 0 は全体 |
||
| 398 | '04 process-001 2025/06/27 12:36:59 START' |
||
| 399 | >>> mobj[1] # インデックス数値指定 1 が最初の (...) 部分 |
||
| 400 | '04' |
||
| 401 | >>> mobj[2] |
||
| 402 | 'process-001' |
||
| 403 | >>> mobj.group(3) # group() 数値指定 |
||
| 404 | '2025/06/27' |
||
| 405 | >>> mobj.group(4) |
||
| 406 | '12:36:59' |
||
| 407 | >>> mobj.group(5) |
||
| 408 | 'START' |
||
| 409 | >>> mobj.group(3,4,5) # 複数指定でタプルを取得 |
||
| 410 | ('2025/06/27', '12:36:59', 'START') |
||
| 411 | >>> mobj.group(6) # (...) は 5 個なので、6 は範囲外エラー |
||
| 412 | Traceback (most recent call last): |
||
| 413 | File "<python-input-46>", line 1, in <module> |
||
| 414 | mobj.group(6) |
||
| 415 | ~~~~~~~~~~^^^ |
||
| 416 | IndexError: no such group |
||
| 417 | ``` |
||
| 418 | - 正規表現に名前付きグループを指定することで、サブグループ取得時にグループ名を使用可能 |
||
| 419 | - 名前付きグループ `(?P<name>...)` |
||
| 420 | ```python |
||
| 421 | >>> import re |
||
| 422 | >>> pat = re.compile(r"(?P<num>\d\d) (?P<id>[^ ]+) (?P<date>\d{4}/\d{2}/\d{2}) (?P<time>\d{2}:\d{2}:\d{2}) (?P<message>\.+)") |
||
| 423 | >>> mobj = pat.match("04 process-001 2025/06/27 12:36:59 START") |
||
| 424 | >>> mobj[2] |
||
| 425 | 'process-001' |
||
| 426 | >>> mobj["id"] |
||
| 427 | 'process-001' |
||
| 428 | >>> mobj.group(2) |
||
| 429 | 'process-001' |
||
| 430 | >>> mobj.group(3) |
||
| 431 | '2025/06/27' |
||
| 432 | >>> mobj.group("message") |
||
| 433 | 'START' |
||
| 434 | ``` |
||
| 435 | - マッチオブジェクトのメソッド |
||
| 436 | |メソッド名|解説|戻り値| |
||
| 437 | |---|---|---| |
||
| 438 | |`groups(default=None)`|パターンにマッチしたサブグループの文字列をタプルで返す<br>`defalt` はマッチ文字列が無い場合に返す値の指定|tuple| |
||
| 439 | |`groupdict(default=None)`|`groups()` と同様だが、グループ名をキーとした辞書を返す<br>グループ名を付けていない場合は空の辞書|dict| |
||
| 440 | |`expand(template)`|文字列 template で `\1` `\g<name>` 形式でサブグループを指定すると、マッチした文字列に置換されて返される|str| |
||
| 441 | |||
| 442 | ```python |
||
| 443 | >>> import re |
||
| 444 | >>> pat = re.compile(r"(\d\d) ([^ ]+) (\d{4}/\d{2}/\d{2}) (\d{2}:\d{2}:\d{2}) (.+)") |
||
| 445 | >>> pat_n = re.compile(r"(?P<num>\d\d) (?P<id>[^ ]+) (?P<date>\d{4}/\d{2}/\d{2}) (?P<time>\d{2}:\d{2}:\d{2}) (?P<messag\e>.+)") |
||
| 446 | >>> mobj = pat.match("04 process-001 2025/06/27 12:36:59 START") |
||
| 447 | >>> mobj_n = pat_n.match("04 process-001 2025/06/27 12:36:59 START") |
||
| 448 | >>> mobj.groupdict() |
||
| 449 | {} |
||
| 450 | >>> mobj_n.groupdict() |
||
| 451 | {'num': '04', 'id': 'process-001', 'date': '2025/06/27', 'time': '12:36:59', 'message': 'START'} |
||
| 452 | >>> mobj.groups() |
||
| 453 | ('04', 'process-001', '2025/06/27', '12:36:59', 'START') |
||
| 454 | >>> mobj_n.groups() |
||
| 455 | ('04', 'process-001', '2025/06/27', '12:36:59', 'START') |
||
| 456 | >>> mobj.expand(r"log: \3 \2 \5") |
||
| 457 | 'log: 2025/06/27 process-001 START' |
||
| 458 | ``` |
||
| 459 | |||
| 460 | ## 6.4 Unicode データベースへアクセスする unicodedata |
||
| 461 | |||
| 462 | - Unicode 「文字」と「文字の名前」を変換する |
||
| 463 | - 関数 `lookup(name)` : 指定された名前に対応する文字を返す |
||
| 464 | - 存在しない場合は **KeyError** を返す |
||
| 465 | - 関数 `name(chr[, default])` : 文字 chr に対応する名前を返す |
||
| 466 | - 名前が定義されていない場合、default が指定されていればその値、そうでなければ **ValueError** を返す |
||
| 467 | ```python |
||
| 468 | >>> import unicodedata |
||
| 469 | >>> unicodedata.lookup('BEER MUG') |
||
| 470 | '🍺' |
||
| 471 | >>> unicodedata.name('あ') |
||
| 472 | 'HIRAGANA LETTER A' |
||
| 473 | >>> unicodedata.name('た') |
||
| 474 | 'HIRAGANA LETTER TA' |
||
| 475 | >>> unicodedata.name('石') |
||
| 476 | 'CJK UNIFIED IDEOGRAPH-77F3' |
||
| 477 | ``` |
||
| 478 | - Unicode 文字列の正規化 |
||
| 479 | - 関数 `normalize(form, unistr)` で、正規化した文字列を取得できる |
||
| 480 | - `form` : 正規化の形式指定 (`NFC` `NFKC` `NFD` `NFKD` のいずれか) |
||
| 481 | - `unistr` : 正規化する文字列 |
||
| 482 | - 戻り値 : 正規化された文字列 |
||
| 483 | ```python |
||
| 484 | >>> import unicodedata |
||
| 485 | >>> target = 'あかざだぱ①②ⅠⅡ¹²₁₂' |
||
| 486 | >>> target |
||
| 487 | 'あかざだぱ①②ⅠⅡ¹²₁₂' |
||
| 488 | >>> unicodedata.normalize('NFC', target) |
||
| 489 | 'あかざだぱ①②ⅠⅡ¹²₁₂' |
||
| 490 | >>> unicodedata.normalize('NFD', target) |
||
| 491 | 'あかざだぱ①②ⅠⅡ¹²₁₂' |
||
| 492 | >>> unicodedata.normalize('NFKC', target) |
||
| 493 | 'あかざだぱ12III1212' |
||
| 494 | >>> unicodedata.normalize('NFKD', target) |
||
| 495 | 'あかざだぱ12III1212' |
||
| 496 | ``` |
||
| 497 | - 正規化形式について (独自追加調査) |
||
| 498 | ||正準等価性で分解|互換等価性で分解| |
||
| 499 | |:-:|:-:|:-:| |
||
| 500 | |**正準等価性で合成**|NFC|NFKC| |
||
| 501 | |**合成無し**|NFD|NFKD| |
||
| 502 | - 全角と半角、数字と丸数字・下付き数字・上付き数字 |
||
| 503 | - 正準等価ではない |
||
| 504 | - 互換等価である |
||
| 505 | - `NFC` `NFKC` の「合成」 : 濁音などは「分解」でわかれるが、それを1文字として再合成する |
||
| 506 | ```python |
||
| 507 | >>> import unicodedata |
||
| 508 | >>> target = 'あかざだぱ①②ⅠⅡ¹²₁₂' |
||
| 509 | |||
| 510 | # NFC: 正準分解、合成 |
||
| 511 | >>> list(unicodedata.normalize('NFC', target)) |
||
| 512 | ['あ', 'か', 'ざ', 'だ', 'ぱ', '①', '②', 'Ⅰ', 'Ⅱ', '¹', '²', '₁', '₂'] |
||
| 513 | |||
| 514 | # NFD: 正準分解、合成無し (list にすると、濁音が分かれている) |
||
| 515 | >>> list(unicodedata.normalize('NFD', target)) |
||
| 516 | ['あ', 'か', 'さ', '゙', 'た', '゙', 'は', '゚', '①', '②', 'Ⅰ', 'Ⅱ', '¹', '²', '₁', '₂'] |
||
| 517 | |||
| 518 | # NFKC: 互換分解(丸数字、上下付き数字が通常の数字に)、合成 |
||
| 519 | >>> list(unicodedata.normalize('NFKC', target)) |
||
| 520 | ['あ', 'か', 'ざ', 'だ', 'ぱ', '1', '2', 'I', 'I', 'I', '1', '2', '1', '2'] |
||
| 521 | |||
| 522 | # NFKC: 互換分解(丸数字、上下付き数字が通常の数字に)、合成無し (list にすると、濁音が分かれている) |
||
| 523 | >>> list(unicodedata.normalize('NFKD', target)) |
||
| 524 | ['あ', 'か', 'さ', '゙', 'た', '゙', 'は', '゚', '1', '2', 'I', 'I', 'I', '1', '2', '1', '2'] |
||
| 525 | ``` |
||
| 526 | - 日本語の正規化には `NFKC` がよく使用される |
||
| 527 | - 検索などで、表記ゆれを吸収して検索するのに使用される |