2

テンプレートと事前定義されたブロックのセットに基づいて正規表現を作成し、置換にstring.Templateを使用したいと思います。

例えば:

  • レンプレート:/data/${year}_${month}_${day}/${year}${month}${day}_${type}_${id}.dat
  • ブロック:
    • 日: (?P<day>\d{2})
    • 月: (?P<month>\d{2})
    • 年: (?P<year>\d{4})
    • タイプ: (?P<typechar>[BDPCLNIYSQJ])
    • id: (?P<id>\d{8})

>>> string.Template(template).safe_substitute(blocks)

/data/(?P<year>\d{4})_(?P<month>\d{2})_(?P<day>\d{2})/(?P<year>\d{4})(?P<month>\d{2})(?P<day>\d{2})_(?P<typechar>[BDPCLNIYSQJ])_(?P<id>\d{8}).dat

問題は、正規表現で受け入れられない重複した名前グループにあります。

テンプレートを修正する方法(置換の前または後)、重複を飲み込むためにreをだます方法、または問題への完全に新しいアプローチのいずれかを探しています。

4

4 に答える 4

2

Python についてはわかりませんが、PCRE と Perl の両方が (?(DEFINE)...) 構造をサポートしています。だからあなたはこのようなものを使うことができます

(?x) 
(?(DEFINE)
    (?<date>        (?&long_date) | (?&short_date))
    (?<long_date>   (?&year) _ (?&month) _ (?&day) _ (?&type) _ (?&id))
    (?<short_date>  (?&year) _ (?&month) _ (?&day))
    (?<day>         \d{2})
    (?<month>       \d{2})
    (?<year>        \d{4})
    (?<type>        [BDPCLNIYSQJ])
    (?<id>          \d{8})
)
(?&date)

正規表現を読みやすくするために、「x」修飾子 (?x) を使用しました (正規表現内の空白は無視されます)。

(?(DEFINE)...) の形式の「条件付きグループ」を使用して、インラインで評価されることのないグループ (名前と番号が付けられている) を定義できますが、他の場所から「サブルーチン」として呼び出すことができます。実際には、DEFINE 条件は常に false です。そのようなグループには、選択肢が 1 つしかない場合があります。

http://www.pcre.org/changelog.txt

于 2013-01-29T12:30:23.520 に答える
0

テンプレートを2回適用します。1回は名前を設定し、出力を使用して最終的な正規表現を作成します。

day='(?P<$dayname>\d{2})'
d=dict(dayname='day_start')
Template(day).safe_substitute(d)

必要なすべての名前について繰り返し、それらすべてを、day1、day2などを使用する最終的なテンプレートにフィードします。

于 2013-01-29T12:15:31.543 に答える
0

友人のアドバイスに従って、望ましい結果を達成する方法を見つけました。

アイデアは、正規表現ブロックを置き換える前に、テンプレート文字列を変更して重複する変数を排除することです。実際、重複を削除するのではなく、最初の重複を (?P=name) 構文で参照して置き換えます。このようにして、そのブロックを使用するすべての場所で内容が同じになるように強制します。

正規表現グループ名はテンプレート ブロック名と同じであると仮定します。質問例ではそうではありませんが、問題なく変更できます。

複製を変換するには、次の関数を使用します。

>>> def remove_duplicate_blocks(template):
        regex = '\$\{([\w]+)\}'
        def alt_seen(matchobj):
            x = matchobj.group(1)
            if x not in seen and not seen_add(x): return '${%s}' % x
            else: return '(?P=%s)' % x
        seen = set()
        seen_add = seen.add
        return re.sub(regex, alt_seen, template)

これは、複製なしで変換されたテンプレートを返し、すべての同様のブロックが同じコンテンツを持つように強制します。

後はブロックを入れ替えるだけです

>>> unique_blocks_template = remove_duplicate_blocks(template)
>>> print unique_blocks_template
/data/${year}_${month}_${day}/(?P=year)(?P=month)(?P=day)_${type}_${id}.dat

>>> string.Template(unique_blocks_template).safe_substitute(blocks)
'/data/(?P<year>\\d{4})_(?P<month>\\d{2})_(?P<day>\\d{2})/(?P=year)(?P=month)(?P=day)_(?P<type>[BDPCLNIYSQJ])_(?P<id>\\d{8}).dat'

質問には記載されていませんが、同じ元のテンプレートを使用して、正規表現と照合する文字列を再構築することもできます。これが、このコードの本来の目的です。

于 2013-01-29T22:57:33.353 に答える
0

?P name 要素を取り除きます。すなわち

day: (?P<name>\d{2})

になる

day: (\d{2})

tbh の前に ?P 機能を使用したことがない

ただし、正規表現テンプレートのアイデアは良いです!

于 2013-01-29T11:49:00.370 に答える