Table of Contents
はじめに
文字列処理は、データを扱っていれば必ず通る領域です。この記事では、正規表現・JSON・ハッシュ値まわりで実際に使う処理をまとめました。
re.findall で文字列を抽出する
re.findall() は、パターンに一致した部分をすべてリストで返します。
import re
s = "I love penguins. I love bears."
re.findall(r"I love penguins.", s)# ['I love penguins.']丸括弧の有無で結果が変わる
ここが findall のいちばん重要な仕様です。
# 括弧なし: 一致した全体が返るre.findall(r"I love penguins.", s)# ['I love penguins.']
# 括弧あり: 括弧の中だけが返るre.findall(r"I love (penguins).", s)# ['penguins']
# (?:...) はグループ化するが抽出はしないre.findall(r"I love (?:penguins|bears).", s)# ['I love penguins.', 'I love bears.'](...) はキャプチャグループといい、findall はそこだけを取り出します。一方 (?:...) は非キャプチャグループで、| を使うために括る場合など「まとめたいだけ」のときに使います。
意図せず括弧を使うと結果が変わってしまうので、抽出したい部分だけを (...) で囲むのが基本です。
AND条件とOR条件を書き分ける
正規表現では、この2つの書き方がまったく違います。
OR条件(どれかに一致)
| で区切ります。
re.findall(r"ねこ|いぬ", "ねこといぬ")# ['ねこ', 'いぬ']AND条件(すべてを含む)
| ではAND条件になりません。先読み (?=...) を重ねます。
import re
# 「ねこ」と「いぬ」の両方を含むかpattern = r"(?=.*ねこ)(?=.*いぬ)"
bool(re.search(pattern, "ねこといぬ")) # Truebool(re.search(pattern, "ねこだけ")) # False(?=...) は「この位置から先に、この条件を満たす部分がある」という判定だけを行い、文字を消費しません。そのため複数重ねると「すべて満たす」という意味になります。
文字の重複がない単語を抽出する
すべての文字が1回ずつしか現れない単語を取り出します。
words = ["about", "is", "cat", "skill", "test"]
[w for w in words if len(set(w)) == len(w)]# ['about', 'is', 'cat']set() は重複を除いた集合を作るので、元の長さと一致すれば重複がないと判定できます。1行で済むうえに意図も読み取りやすい書き方です。
日本語のJSONが文字化けする
日本語を含む辞書を json.dumps() すると、\uXXXX 形式にエンコードされます。
import json
j = [{"項目名": "値"}]print(json.dumps(j))# [{"\u9805\u76ee\u540d": "\u5024"}]ensure_ascii=False を付ければ、そのまま出力されます。
print(json.dumps(j, ensure_ascii=False))# [{"項目名": "値"}]ファイルに書き出すときも同様です。読みやすく整形する indent と併せて指定することが多いです。
with open("data.json", "w", encoding="utf-8") as f: json.dump(j, f, ensure_ascii=False, indent=2)ハッシュ値を生成する
hashlib を使います。文字列は先にバイト列へ変換します。
import hashlib
value = "hogefuga"
hashlib.md5(value.encode()).hexdigest()hashlib.sha256(value.encode()).hexdigest()アルゴリズム名を変えるだけで切り替えられます。
ファイルのハッシュ値を取る場合は、メモリに全部載せずに少しずつ読み込みます。
import hashlib
def file_hash(path): h = hashlib.sha256() with open(path, "rb") as f: for chunk in iter(lambda: f.read(8192), b""): h.update(chunk) return h.hexdigest()おわりに
正規表現は、findall の括弧の扱いと、AND条件が | では書けないという2点を押さえておけば、大半の場面で困りません。凝ったパターンを1つ書くより、Pythonの条件式に分けたほうが読みやすくなることも多いので、無理に正規表現だけで解こうとしないのがコツです。
