1

バージョン形式の文字列を解析する Python ライブラリを作成しようとしています。(簡略化された) バージョン文字列の形式は次のとおりです。

<product>-<x>.<y>.<z>[-alpha|beta|rc[.<n>]][.<extra>]][.centos|redhat|win][.snb|ivb]

これは:

  • 製品、すなわちfoo
  • 数値バージョン、つまり:0.1.0
  • [オプション] プレリリース情報、つまり: beta, rc.1,alpha.extrainfo
  • [オプション] オペレーティング システム、つまり:centos
  • [オプション] プラットフォーム、つまり: snb,ivb

したがって、以下は有効なバージョン文字列です。

1) foo-1.2.3
2) foo-2.3.4-alpha
3) foo-3.4.5-rc.2
4) foo-4.5.6-rc.2.extra
5) withos-5.6.7.centos
6) osandextra-7.8.9-rc.extra.redhat
7) all-4.4.4-rc.1.extra.centos.ivb

これらすべての例で、次の正規表現は正常に機能します。

^(?P<prod>\w+)-(?P<maj>\d).(?P<min>\d).(?P<bug>\d)(?:-(?P<pre>alpha|beta|rc)(?:\.(?P<pre_n>\d))?(?:\.(?P<pre_x>\w+))?)?(?:\.(?P<os>centos|redhat|win))?(?:\.(?P<plat>snb|ivb))?$

しかし、このタイプのバージョンで問題が発生します (「追加の」プレリリース情報はありませんが、OS やプラットフォームに問題があります):

8) issue-0.1.0-beta.redhat.snb

上記の正規表現では、文字列 #8が、グループではなくredhatプレリリースの extra info で取得されています。pre_xos

でosまたはプラットフォーム文字列を選択しないように、後読みを使用してみましたpre_x

...(?:\.(?P<pre_x>\w+))?(?<!centos|redhat|win|ivb|snb))...

あれは:

^(?P<prod>\w+)-(?P<maj>\d).(?P<min>\d).(?P<bug>\d)(?:-(?P<pre>alpha|beta|rc)(?:\.(?P<pre_n>\d))?(?:\.(?P<pre_x>\w+))?(?<!centos|redhat|win|ivb|snb))?(?:\.(?P<os>centos|redhat|win))?(?:\.(?P<plat>snb|ivb))?$

reこれは、Python の標準モジュールが可変幅の後読みを受け入れることができる場合にうまく機能します。私のライブラリは、依存関係を制限したい多数のマシンに配布される可能性が非常に高いため、正規表現を使用するのではなく、標準モジュールに固執することをお勧めします。

同様の質問も見てきました: thisthis、およびthisは適用できません。

これを達成する方法についてのアイデアはありますか?

私の正規表現リンク: https://regex101.com/r/bH0qI7/3

[興味のある方のために、これは私が実際に使用している完全な正規表現です: https://regex101.com/r/lX7nI6/2]

4

2 に答える 2

2

または(?P<pre_x>\w+)以外のいずれかに一致させるには、否定先読みアサーションを使用する必要があります。centosredhat

^(?P<prod>\w+)-(?P<maj>\d)\.(?P<min>\d)\.(?P<bug>\d)(?:-(?P<pre>alpha|beta|rc)(?:\.(?P<pre_n>\d))?(?:\.(?:(?!centos|redhat)\w)+)?)?(?:\.(?P<os>centos|redhat))?(?:\.(?P<plat>snb|ivb))?$

デモ

于 2015-05-27T13:54:45.877 に答える
1

実際、私は正規表現の使用を避けたいと思います。なぜなら、それはすでにかなりひどいものに見えるからです。手で解析する方がはるかに読みやすいです。

def extract(text):
    parts = text.split('-')
    ret = {}
    ret['name'] = parts.pop(0)
    ret['version'] = parts.pop(0).split('.')

    if len(parts) > 0:
        rest_parts = parts.pop(0).split('.')
        if rest_parts[-1] in ['snb', 'ivb']:
            ret['platform'] = rest_parts.pop(-1)
        if rest_parts[-1] in ['redhat', 'centos', 'win']:
            ret['os'] = rest_parts.pop(-1)
        ret['extra'] = rest_parts

    return ret

tests = \
[
    'foo-1.2.3',
    'foo-2.3.4-alpha',
    'foo-3.4.5-rc.2',
    'foo-4.5.6-rc.2.extra',
    'withos-5.6.7.centos',
    'osandextra-7.8.9-rc.extra.redhat',
    'all-4.4.4-rc.1.extra.centos.ivb',
    'issue-0.1.0-beta.redhat.snb',
]

for test in tests:
    print(test, extract(test))

結果:

('foo-1.2.3', {'version': ['1', '2', '3'], 'name': 'foo'})
('foo-2.3.4-alpha', {'version': ['2', '3', '4'], 'name': 'foo', 'extra': ['alpha']})
('foo-3.4.5-rc.2', {'version': ['3', '4', '5'], 'name': 'foo', 'extra': ['rc', '2']})
('foo-4.5.6-rc.2.extra', {'version': ['4', '5', '6'], 'name': 'foo', 'extra': ['rc', '2', 'extra']})
('withos-5.6.7.centos', {'version': ['5', '6', '7', 'centos'], 'name': 'withos'})
('osandextra-7.8.9-rc.extra.redhat', {'version': ['7', '8', '9'], 'os': 'redhat', 'name': 'osandextra', 'extra': ['rc', 'extra']})
('all-4.4.4-rc.1.extra.centos.ivb', {'platform': 'ivb', 'version': ['4', '4', '4'], 'os': 'centos', 'name': 'all', 'extra': ['rc', '1', 'extra']})
('issue-0.1.0-beta.redhat.snb', {'platform': 'snb', 'version': ['0', '1', '0'], 'os': 'redhat', 'name': 'issue', 'extra': ['beta']})
于 2015-05-27T14:04:40.650 に答える