実現したいこと
PYTHON 3.10で正規表現を使った文字列の置き換えをしています。
自前でエスケープシーケンスを処理しようとしていますが行き詰まっています。
試行錯誤中のコードを掲載いたします。
アドバイスよろしくお願い致します。
前提
- \はエスケープシーケンス文字として扱う
- \1はグループ1の文字列として扱う
- グループは0から9までに対応する
- \\は\の文字列に置き換えられる
- \\\1は\とグループ1の文字列に置き換えられる
コード
以下のようなテストコードを使って試しています。
テストではグループ1固定のコードになっています。
PYTHON
1# Versions confirmed to work : PYTHON 3.10.11 on Windows 10 2# -*- coding: utf-8 -*- 3 4import re 5 6# \はエスケープシーケンス文字として扱う 7# \1はグループ1の文字列として扱う 8# グループは0から9までに対応する 9# \\1は\1の文字列に置き換えられる 10# \\\1は\とグループ1の文字列に置き換えられる 11 12# エスケープシーケンスの奇数回・偶数回のマッチ用文字列 13reg_odd = r"((?<!\\)\\(?:\\\\)*(?!\\))" # 奇数回マッチ 14reg_even = r"((?<!\\)(?:\\\\)+(?!\\))" # 偶数回マッチ 15 16target_str = r"o:(\1) x:(\\1) o:(\\\1) x:(\\\\1) o:(\\\\\1)" 17regex_str = reg_even + r"?\\1" 18replace_str = r"A" 19 20result_str = re.sub(regex_str, replace_str, target_str) 21 22print(r"Target String : {}".format(target_str)) 23print(r"Test Result : {}".format(result_str)) 24print(r"Correct Result : o:(A) x:(\1) o:(\A) x:(\\1) o:(\\A)") 25
試したこと
0または偶数回のエスケープシーケンス文字のあとの\1を置き換えれば良いと考え試行錯誤をしています。
補足情報(FW/ツールのバージョンなど)
OS : Windows 10
完成しました♪
おかげ様でいちおうの完成をしましたのでコードを掲載いたします。
ありがとうございました。
PYTHON
1# Versions confirmed to work : PYTHON 3.10.11 on Windows 10 2# -*- coding: utf-8 -*- 3 4 5def unescape_str(target_str: str, replace_str: list) -> str: 6 """ 7 エスケープシーケンスの実装 8 9 1. "\"はエスケープシーケンス文字として扱う 10 2. "\1"はグループ1の文字列として扱う 11 3. グループは0から9までに対応する 12 4. "\\"は"\"の文字列に置き換えられる 13 5. "\\\1"は"\"とグループ1の文字列に置き換えられる 14 6. エスケープシーケンスに続く文字が数字以外の場合はそのまま出力する 15 16 Args: 17 target_str (str): 置き換え対象の文字列 18 replace_str (list): "\"に続く数字(0-9) の置換対象リスト 19 replace_strが10未満の場合は、10になるまで空文字列で補完する 20 Returns: 21 str: 置き換え後の文字列 22 """ 23 import re 24 25 # エスケープシーケンスの正規表現 26 # regex_str = r"(?<!\\)((?:\\)+)(\d+)?" 27 regex_str = r"((?:\\)+)(\d+)?" # 多分こっちで十分 28 29 # 置き換え文字列のリストの長さを10に補完する 30 for i in range(len(replace_str), 10): 31 replace_str.append("") 32 33 # エスケープシーケンスの置き換え関数 34 def regex_replace_rtn(matches): 35 matches_length = len(matches.group(1)) 36 tail = matches.group(2) 37 if matches_length % 2 == 0: 38 if tail is None: 39 tail = "" 40 else: 41 if tail is None: 42 # (奇数の)エスケープシーケンスに続く文字が数字以外 43 # raise ValueError("Escape sequence followed by a non-numeric character") 44 tail = "\\" 45 else: 46 tail = replace_str[int(tail)] 47 return "\\" * (matches_length // 2) + str(tail) 48 49 result_str = re.sub(regex_str, regex_replace_rtn, target_str) 50 return result_str 51 52 53if __name__ == "__main__": 54 # Test Code : Sequential escape characters 55 target_str = r"o:(\1) x:(\\1) o:(\\\1) x:(\\\\1) o:(\\\\\1) (\\\\\n)" 56 Correct_Result = r"o:(B) x:(\1) o:(\B) x:(\\1) o:(\\B) (\\\n)" 57 replace_str = ["A", "B", "C"] # \数字 の置換対象リスト 58 result_str = unescape_str(target_str, replace_str) 59 60 print(r"Target String :", target_str) 61 print(r"Test Result :", result_str) 62 print(r"Correct Result :", Correct_Result) 63 print(r"Match :", (result_str == Correct_Result)) 64 65 # Test Code : Replacing escape characters 66 target_str = r"(\0) (\1) (\2) (\3) (\4) (\5) (\6) (\7) (\8) (\9) (\x)" 67 replace_str = ["A", "B", "C"] # \Number(0-9) replacement character list 68 result_str = unescape_str(target_str, replace_str) 69 70 print(r"Target String :", target_str) 71 print(r"Test Result :", result_str) 72
回答2件
あなたの回答
tips
プレビュー