web-dev-qa-db-ja.com

バージョン番号解析の正規表現

次の形式のバージョン番号があります。

version.release.modification

ここで、バージョン、リリース、および変更は、数字のセットまたは「*」ワイルドカード文字のいずれかです。さらに、これらの番号(および先行する。)のいずれかが欠落している場合があります。

したがって、以下は有効であり、次のように解析されます。

1.23.456 = version 1, release 23, modification 456
1.23     = version 1, release 23, any modification
1.23.*   = version 1, release 23, any modification
1.*      = version 1, any release, any modification
1        = version 1, any release, any modification
*        = any version, any release, any modification

しかし、これらは無効です。

*.12
*123.1
12*
12.*.34

誰でも私にあまり複雑ではない正規表現を提供して、リリース、バージョン、および修正番号を検証および取得できますか?

73
Andrew Borley

私はフォーマットを次のように表現します:

「1〜3個のドットで区切られたコンポーネント。最後のコンポーネントが*である可能性があることを除いて、それぞれ数値です。」

正規表現として、それは:

^(\d+\.)?(\d+\.)?(\*|\d+)$

[追加して編集:このソリューションは検証するための簡潔な方法ですが、値の抽出には余分な作業が必要であることが指摘されています。正規表現を複雑にするか、一致したグループを処理することでこれに対処するかどうかは好みの問題です。

私のソリューションでは、グループは"."文字をキャプチャします。これは、ajborleyの答えのように、非キャプチャグループを使用して処理できます。

また、右端のグループは、コンポーネントが3つより少ない場合でも最後のコンポーネントをキャプチャします。したがって、たとえば2コンポーネントの入力では、最初と最後のグループがキャプチャされ、真ん中のグループが未定義になります。サポートされている場合、これは貪欲でないグループによって対処できると思います。

正規表現後の両方の問題に対処するPerlコードは、次のようになります。

@version = ();
@groups = ($1, $2, $3);
foreach (@groups) {
    next if !defined;
    s/\.//;
    Push @version, $_;
}
($major, $minor, $mod) = (@version, "*", "*");

これは"."で分割するよりも短くありません

76
Steve Jessop

正規表現を使用すると、2つの問題が発生します。ドット( "。")で分割し、各部分がワイルドカードまたは数字のセットであることを確認します(正規表現は完全になりました)。事が有効な場合は、分割の正しいチャンクを返すだけです。

38
Paweł Hajdan

これはうまくいくかもしれません:

^(\*|\d+(\.\d+){0,2}(\.\*)?)$

トップレベルでは、「*」は有効なバージョン番号の特殊なケースです。それ以外の場合は、数字で始まります。次に、0、1、または2つの「.nn」シーケンスがあり、その後にオプションの「。*」が続きます。この正規表現は、アプリケーションで許可される場合と許可されない場合がある1.2.3。*を受け入れます。

一致したシーケンスを取得するためのコード、特に(\.\d+){0,2}部分は、特定の正規表現ライブラリに依存します。

11
Greg Hewgill

すべての回答をありがとう!これはエースです:)

OneByOneの回答(私には最も簡単に見えた)に基づいて、非キャプチャグループを追加しました( '(?:'パーツ-非キャプチャグループに私を紹介してくれたVonCに感謝します!)数字または*文字が含まれます。

^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$

みんなありがとう!

11
Andrew Borley

私の2セント:このシナリオがありました:文字列リテラルからバージョン番号を解析する必要がありました。 (これは元の質問とは非常に異なることを知っていますが、バージョン番号を解析するための正規表現を見つけるためにグーグルで検索すると、このスレッドが先頭に表示されたので、この答えをここに追加します)

したがって、文字列リテラルは次のようになります。「サービスバージョン1.2.35.564が実行されています!」

このリテラルから1.2.35.564を解析する必要がありました。 @ajborleyからヒントを得て、私の正規表現は次のとおりです。

(?:(\d+)\.)?(?:(\d+)\.)?(?:(\d+)\.\d+)

これをテストするための小さなC#スニペットは次のようになります。

void Main()
{
    Regex regEx = new Regex(@"(?:(\d+)\.)?(?:(\d+)\.)?(?:(\d+)\.\d+)", RegexOptions.Compiled);

    Match version = regEx.Match("The Service SuperService 2.1.309.0) is Running!");
    version.Value.Dump("Version using RegEx");   // Prints 2.1.309.0        
}
7

使用しているプラ​​ットフォームがわかりませんが、.NETには、「n.n.n.n」バージョン番号を解析するSystem.Versionクラスがあります。

7
Duncan Smart

私は、分割提案に同意する傾向があります。

IveはPerlの問題に対する「テスター」を作成しました

#!/usr/bin/Perl -w


@strings = ( "1.2.3", "1.2.*", "1.*","*" );

%regexp = ( svrist => qr/(?:(\d+)\.(\d+)\.(\d+)|(\d+)\.(\d+)|(\d+))?(?:\.\*)?/,
            onebyone => qr/^(\d+\.)?(\d+\.)?(\*|\d+)$/,
            greg => qr/^(\*|\d+(\.\d+){0,2}(\.\*)?)$/,
            vonc => qr/^((?:\d+(?!\.\*)\.)+)(\d+)?(\.\*)?$|^(\d+)\.\*$|^(\*|\d+)$/,
            ajb => qr/^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/,
            jrudolph => qr/^(((\d+)\.)?(\d+)\.)?(\d+|\*)$/
          );

  foreach my $r (keys %regexp){
    my $reg = $regexp{$r};
    print "Using $r regexp\n";
foreach my $s (@strings){
  print "$s : ";

    if ($s =~m/$reg/){
    my ($main, $maj, $min,$rev,$ex1,$ex2,$ex3) = ("any","any","any","any","any","any","any");
    $main = $1 if ($1 && $1 ne "*") ;
    $maj = $2 if ($2 && $2 ne "*") ;
    $min = $3 if ($3 && $3 ne "*") ;
    $rev = $4 if ($4 && $4 ne "*") ;
    $ex1 = $5 if ($5 && $5 ne "*") ;
    $ex2 = $6 if ($6 && $6 ne "*") ;
    $ex3 = $7 if ($7 && $7 ne "*") ;
    print "$main $maj $min $rev $ex1 $ex2 $ex3\n";

  }else{
  print " nomatch\n";
  }
  }
print "------------------------\n";
}

現在の出力:

> Perl regex.pl
Using onebyone regexp
1.2.3 : 1. 2. 3 any any any any
1.2.* : 1. 2. any any any any any
1.* : 1. any any any any any any
* : any any any any any any any
------------------------
Using svrist regexp
1.2.3 : 1 2 3 any any any any
1.2.* : any any any 1 2 any any
1.* : any any any any any 1 any
* : any any any any any any any
------------------------
Using vonc regexp
1.2.3 : 1.2. 3 any any any any any
1.2.* : 1. 2 .* any any any any
1.* : any any any 1 any any any
* : any any any any any any any
------------------------
Using ajb regexp
1.2.3 : 1 2 3 any any any any
1.2.* : 1 2 any any any any any
1.* : 1 any any any any any any
* : any any any any any any any
------------------------
Using jrudolph regexp
1.2.3 : 1.2. 1. 1 2 3 any any
1.2.* : 1.2. 1. 1 2 any any any
1.* : 1. any any 1 any any any
* : any any any any any any any
------------------------
Using greg regexp
1.2.3 : 1.2.3 .3 any any any any any
1.2.* : 1.2.* .2 .* any any any any
1.* : 1.* any .* any any any any
* : any any any any any any any
------------------------
5
svrist

これは、あなたが規定したものに対して機能するはずです。ワイルドカードの位置に依存し、ネストされた正規表現です。

^((\*)|([0-9]+(\.((\*)|([0-9]+(\.((\*)|([0-9]+)))?)))?))$

http://imgur.com/3E492.png

4
nomuus

私は多くの答えを見てきましたが、...私は新しいものを持っています。少なくとも私には有効です。新しい制限を追加しました。バージョン番号は、ゼロで始まり、その後に他のものが続く(メジャー、マイナー、またはパッチ)ことはできません。

01.0.0は無効1.0.0は有効10.0.10は有効1.0.0000は無効

^(?:(0\\.|([1-9]+\\d*)\\.))+(?:(0\\.|([1-9]+\\d*)\\.))+((0|([1-9]+\\d*)))$

以前のものに基づいています。しかし、私はこの解決策をよく見ています...私にとっては;)

楽しい!!!

4
Israel Romero

別の試み:

^(((\d+)\.)?(\d+)\.)?(\d+|\*)$

これにより、グループ4,5,6の3つの部分が得られますが、それらは右に揃えられます。したがって、4,5または6の最初の非ヌルの1つは、バージョンフィールドを提供します。

  • 1.2.3は1,2,3を与えます
  • 1.2。*は1,2、*を与えます
  • 1.2はnull、1,2を返します
  • *** null、null、*を返します
  • 1. *はnull、1、*を返します
3
jrudolph
^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$

おそらくもっと簡潔なものがあります:

^(?:(\d+)\.){0,2}(\*|\d+)$

これは、1.2.3.4.5。*に拡張するか、{0,2}の代わりに*または{2}を使用してX.Y.Zに厳密に制限できます。

3
ofaurax

私はバージョン番号を検索/照合する必要がありました。これは、Mavenの規則または1桁の数字にさえ従います。ただし、修飾子はありません。それは独特で、時間がかかり、それから私はこれを思いつきました:

'^[0-9][0-9.]*$'

これにより、バージョン、

  1. 数字で始まる
  2. 任意の数の数字を使用できます
  3. 数字と「。」のみ許可されています

1つの欠点は、バージョンが「。」で終わることさえあるということです。しかし、それはバージョンの無制限の長さを扱うことができます(あなたがそれを呼び出したいなら、狂ったバージョン管理)

一致:

  • 1.2.3
  • 1.09.5
  • 3.4.4.5.7.8.8。
  • 23.6.209.234.3

「。」に不満がない場合終了、あなたはendswithロジックと組み合わせることができます

3
Shiva

あなたが望むものを正確に実行する正規表現を持つのはかなり難しいようです(つまり、必要なケースのみを受け入れ、拒否しますallその他and3つのコンポーネントのいくつかのグループを返します)。私はそれを試して、これを考え出しました:

^(\*|(\d+(\.(\d+(\.(\d+|\*))?|\*))?))$

IMO(私は広範囲にテストしたことはありません)これは入力のバリデータとしては正常に動作するはずですが、問題はこの正規表現がコンポーネントを取得する方法を提供しないことです。そのためには、期間を分割する必要があります。

このソリューションはオールインワンではありませんが、ほとんどの場合、プログラミングする必要はありません。もちろん、これはコードにある他の制限に依存します。

2
rslite

正規表現は貪欲なので、大きなテキスト内ではなくバージョン番号の文字列内だけを検索する場合は、^と$を使用して文字列の開始と終了をマークします。 Gregの正規表現は正常に機能するようです(エディターで簡単に試してみました)が、ライブラリ/言語によっては、最初の部分が間違ったバージョン番号内の「*」と一致する場合があります。たぶん、私はRegexpを1年ほど使用していないので、何かが欠けているのかもしれません。

これにより、正しいバージョン番号のみが見つかるようになります。

^(\ * |\d +(\。\ d +)*(\。\ *)?)$

編集:実際にグレッグはすでにそれらを追加し、彼のソリューションを改善しました。私は遅すぎます:)

2
FrankS
(?ms)^((?:\d+(?!\.\*)\.)+)(\d+)?(\.\*)?$|^(\d+)\.\*$|^(\*|\d+)$

最初の6つの例と完全に一致し、他の4つの例を拒否します

  • グループ1:majorまたはmajor.minorまたは「*」
  • グループ2(存在する場合):マイナーまたは*
  • グループ3(存在する場合):*

「(?ms)」を削除できます
これを使用して、この正規表現が QuickRex を介して複数行に適用されることを示しました。

2
VonC

XSD要素の指定:

<xs:simpleType>
    <xs:restriction base="xs:string">
        <xs:pattern value="[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(\..*)?"/>
    </xs:restriction>
</xs:simpleType>
2
Emmerson

これは1.2.3。*にも一致します

^(* |\d +(。\ d +){0,2}(。*)?)$

あまりエレガントではないものを提案します。

(* |\d +(。\ d +)?(。*)?)|\d +。\ d +。\ d +)

2
Victor

良い演習として、これについての私の考え- vparse には、 tiny source と単純な関数があります:

function parseVersion(v) {
    var m = v.match(/\d*\.|\d+/g) || [];
    v = {
        major: +m[0] || 0,
        minor: +m[1] || 0,
        patch: +m[2] || 0,
        build: +m[3] || 0
    };
    v.isEmpty = !v.major && !v.minor && !v.patch && !v.build;
    v.parsed = [v.major, v.minor, v.patch, v.build];
    v.text = v.parsed.join('.');
    return v;
}
2
vitaly-t

もう1つのソリューション:

^[1-9][\d]*(.[1-9][\d]*)*(.\*)?|\*$