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


84

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

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

リリース、バージョン、および変更番号を検証および取得するための、それほど複雑ではない正規表現を誰かが私に提供できますか?


「単純な」ものが可能かどうかはわかりません。
svrist 2008

回答:


96

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

「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, "*", "*");

これは、"." ]で分割するよりも実際には短くありません。


1
いくつかの非キャプチャグループを追加すると(以下の私の回答を参照)、キャプチャグループは末尾の「。」をキャプチャしません。^(?:(\ d +)\。)?(?:(\ d +)\。)?(* | \ d +)$ありがとう!
Andrew Borley

非常に素晴らしくクリーンな提案であるということの唯一の問題は、1.2が貪欲さのために最初のグループで1つ、3番目のグループで2つをキャプチャするため、グループが正しくないことです。
jrudolph 2008

39

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


11

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

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

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

一致したシーケンス、特に(\.\d+){0,2}パーツを取得するためのコードは、特定の正規表現ライブラリによって異なります。


素晴らしい答えです!1.2.3.4の一致を防ぐために、エスケープされていない*を{0,2}に交換する必要があると思います。正規表現ライブラリによっては、一致ではなく検索しか実行できない場合は、パターンを^(<pattern>)$で囲むことができます。
Dave Webb

^(* | \ d +(\。\ d +){0,1}(?:(\。*)?|(\。\ d +)?))$を少し変更すると、1.2.3。*も無効になります
Pieter

2
ピーター:今のところはやめようと思います。これはすぐに「2つの問題があります」という領域に入り込んでいます。:)
Greg Hewgill

11

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

OneByOneの回答(私には最も単純に見えた)に基づいて、いくつかの非キャプチャグループを追加しました(「(?:」の部分-非キャプチャグループを紹介してくれたVonCに感謝します!)。数字または*文字を含みます。

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

みんなありがとう!


1
代わりに、これを質問の編集として追加できますか?そうすれば、正しい答えはトップに近くなります
svrist 2008

1
グループ名の場合:^(?:(?<メジャー> \ d +)\。)?(?:(?<マイナー> \ d +)\。)?(?<ビルド> * | \ d +)$
javacavaj

1
semversionをサポートします(もう少し)。-"1.2.3-alpha + abcdedf.lalal" -match "^(?:(\ d +)\。)?(?:(\ d +)\。)?(* | \ d +)?(?:\- ([A-Za-z0-9 \。] +))?(?:\ +([A-Za-z0-9 \。] +))?$ "
Sam

単一の番号で構成されるバージョンの場合(\*|\d+)、最初の^(?:(\d+)\.)?グループではなく3番目のグループと一致することに注意してください。
PiotrDobrogost19年

8

私の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        
}

あなたが別の状況とケースを説明していることは知っていますが、完全を期すために:SemVer 'は'バージョン文字列が '形式X.Y.Z(つまり、正確に3つの部分)である必要があります。ここで、XとYは非負の整数でなければならず、追加の先行ゼロ。semver.orgを参照してください。
Jochem Schulenklopper 2017年

1
@JochemSchulenklopperありがとう、私はSemVerを知っていますが、質問にはSemVerについては何も言及されていません。
Sudhanshu Mishra 2017

1
本当。同僚からSemVer文字列の解析についてこの質問を紹介されたので、答えを読むことができました。
Jochem Schulenklopper 2017年

7

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


いいえ、バージョン1.0以降に存在しています
Duncan Smart

5

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

私は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
------------------------

OneByOneは最も単純なもののように見えるので、それは素晴らしいことです。
jrudolph 2008

間違ったものもテストする必要があります。OneByOneのドットを引用できませんでした。
jrudolph 2008

ドットとその他の正規表現で更新
svrist

4

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

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

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


4

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

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

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

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

楽しい!!!


3

別の試み:

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

これにより、グループ4、5、6の3つの部分が得られますが、これらは右側に配置されています。したがって、4、5、または6の最初のnull以外の値は、バージョンフィールドになります。

  • 1.2.3は1,2,3を与える
  • 1.2。*は1,2、*を与えます
  • 1.2はnull、1,2を与えます
  • ***はnull、null、*を与えます
  • 1. *はnull、1、*を与えます

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

おそらくもっと簡潔なものは次のようになります:

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

次に、これを1.2.3.4.5。*に拡張するか、{0,2}の代わりに*または{2}を使用してXYZに正確に制限することができます。


3

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ロジックと組み合わせることができるかもしれません


:最後の桁を取り除くためには、多分あなたはこの試してみたい(\d+)(.\d+)*
cassioso

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

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

  • グループ1:メジャーまたはmajor.minorまたは '*'
  • 存在する場合はグループ2:マイナーまたは*
  • 存在する場合はグループ3:*

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


2

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

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

私はあまりエレガントではないことを提案します:

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


2

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

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

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

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


2

あなたが(つまり、あなたが必要と拒否というケースのみを受け入れたい正確に何を行い、正規表現持っているかなり難しいようで、すべての人をして3つのコンポーネントのためのいくつかのグループを返すに)。私はそれを試してみて、これを思いつきました:

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

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

このソリューションはオールインワンではありませんが、プログラミングではほとんどの場合、そうする必要はありません。もちろん、これはコードに含まれる可能性のある他の制限によって異なります。


2

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

良い演習としての私の見解-vparseは、ソース小さく、単純な関数です。

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

次のルールに従うバージョン番号を解析する場合:-数字とドットのみである-ドットで開始または終了することはできません-2つのドットを一緒にすることはできません

これは私にトリックをしました。

^(\d+)((\.{1}\d+)*)(\.{0})$

有効なケースは次のとおりです。

1、0.1、1.2.1



1

バージョン番号に英数字のマイナー情報が含まれている場合があります(例:1.2.0bまたは1.2.0-beta)。この場合、私はこの正規表現を使用しています:

([0-9]{1,4}(\.[0-9a-z]{1,6}){1,5})

0

私はこれを見つけました、そしてそれは私のために働きます:

/(\^|\~?)(\d|x|\*)+\.(\d|x|\*)+\.(\d|x|\*)+
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.