it-swarm-vi.tech

Một regex cho phân tích số phiên bản

Tôi có một số phiên bản của mẫu sau:

phiên bản.release.modification

trong đó phiên bản, bản phát hành và sửa đổi là một tập hợp các chữ số hoặc ký tự đại diện '*'. Ngoài ra, bất kỳ số nào trong số này (và bất kỳ số nào trước đó.) Có thể bị thiếu.

Vì vậy, sau đây là hợp lệ và phân tích như:

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

Nhưng những điều này không hợp lệ:

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

Bất cứ ai cũng có thể cung cấp cho tôi một regex không quá phức tạp để xác nhận và truy xuất các bản phát hành, phiên bản và số sửa đổi?

73
Andrew Borley

Tôi muốn thể hiện định dạng là:

"1-3 thành phần được phân tách bằng dấu chấm, mỗi thành phần ngoại trừ số cuối cùng có thể là *"

Là một regrec, đó là:

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

[Chỉnh sửa để thêm: giải pháp này là một cách ngắn gọn để xác thực, nhưng nó đã được chỉ ra rằng việc trích xuất các giá trị đòi hỏi phải làm thêm. Đó là vấn đề của hương vị liệu có nên giải quyết vấn đề này bằng cách làm phức tạp regrec hay xử lý các nhóm khớp.

Trong giải pháp của tôi, các nhóm nắm bắt các ký tự ".". Điều này có thể được xử lý bằng cách sử dụng các nhóm không bắt giữ như trong câu trả lời của ajborley.

Ngoài ra, nhóm ngoài cùng bên phải sẽ nắm bắt thành phần cuối cùng, ngay cả khi có ít hơn ba thành phần, và ví dụ, kết quả đầu vào hai thành phần trong nhóm đầu tiên và nhóm cuối cùng được xác định và nhóm giữa không xác định. Tôi nghĩ rằng điều này có thể được giải quyết bởi các nhóm không tham lam được hỗ trợ.

Mã Perl để giải quyết cả hai vấn đề sau khi regrec có thể giống như thế này:

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

Không thực sự ngắn hơn chia nhỏ trên "."]

76
Steve Jessop

Sử dụng regex và bây giờ bạn có hai vấn đề. Tôi sẽ phân chia thứ đó trên các dấu chấm ("."), Sau đó đảm bảo rằng mỗi phần là ký tự đại diện hoặc bộ chữ số (hiện tại regex hoàn hảo). Nếu điều đó là hợp lệ, bạn chỉ cần trả lại phần chính xác của phần tách.

38
Paweł Hajdan

Điều này có thể làm việc:

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

Ở cấp cao nhất, "*" là trường hợp đặc biệt của số phiên bản hợp lệ. Nếu không, nó bắt đầu với một số. Sau đó, có các chuỗi 0, một hoặc hai ".nn", theo sau là ". *" Tùy chọn. Regex này sẽ chấp nhận 1.2.3. * Có thể hoặc không được phép trong ứng dụng của bạn.

Mã để truy xuất các chuỗi phù hợp, đặc biệt là (\.\d+){0,2} một phần, sẽ phụ thuộc vào thư viện regex cụ thể của bạn.

11
Greg Hewgill

Cảm ơn vì tất cả những phản hồi! Đây là ace :)

Dựa trên câu trả lời của OneByOne (có vẻ đơn giản nhất đối với tôi), tôi đã thêm một số nhóm không bắt giữ (các phần '(?:' - cảm ơn VonC vì đã giới thiệu cho tôi các nhóm không bắt giữ!), Vì vậy các nhóm chỉ chụp chứa các chữ số hoặc ký tự *.

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

Rất cám ơn mọi người!

11
Andrew Borley

2 xu của tôi: Tôi đã có kịch bản này: Tôi đã phải phân tích số phiên bản ra khỏi một chuỗi ký tự. (Tôi biết điều này rất khác so với câu hỏi ban đầu, nhưng việc tìm kiếm một regex để phân tích số phiên bản cho thấy chủ đề này ở đầu, vì vậy hãy thêm câu trả lời này vào đây)

Vì vậy, chuỗi ký tự sẽ là một cái gì đó như: "Phiên bản dịch vụ 1.2.35.564 đang chạy!"

Tôi đã phải phân tích 1,2,35,564 ra khỏi nghĩa đen này. Lấy một gợi ý từ @ajborley, regex của tôi như sau:

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

Một đoạn C # nhỏ để kiểm tra điều này trông như dưới đây:

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
Sudhanshu Mishra

Không biết bạn đang sử dụng nền tảng nào nhưng trong .NET có lớp System.Version sẽ phân tích số phiên bản "n.n.n.n" cho bạn.

7
Duncan Smart

Tôi có xu hướng đồng ý với đề nghị chia.

Ive đã tạo một "người kiểm tra" cho vấn đề của bạn trong 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";
}

Sản lượng hiện tại:

> 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

Điều này sẽ làm việc cho những gì bạn quy định. Nó nằm trên vị trí thẻ hoang dã và là một biểu thức chính quy:

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

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

4
nomuus

Tôi đã thấy rất nhiều câu trả lời, nhưng ... tôi có một câu trả lời mới. Nó làm việc cho tôi ít nhất. Tôi đã thêm một hạn chế mới. Số phiên bản không thể bắt đầu (chính, phụ hoặc vá) với bất kỳ số không nào theo sau bởi các số khác.

01.0.0 không hợp lệ 1.0.0 có hiệu lực 10.0.10 là hợp lệ 1.0.0000 không hợp lệ

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

Nó dựa trên cái trước. Nhưng tôi thấy giải pháp này tốt hơn ... đối với tôi;)

Thưởng thức!!!

4
Israel Romero

Một lần thử khác:

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

Điều này cung cấp cho ba phần trong nhóm 4,5,6 NHƯNG: Chúng được sắp xếp ở bên phải. Vì vậy, lần đầu tiên không có giá trị 4,5 hoặc 6 cung cấp cho trường phiên bản.

  • 1.2.3 cho 1,2,3
  • 1.2. * Cho 1,2, *
  • 1,2 cho null, 1,2
  • *** cho null, null, *
  • 1. * cho null, 1, *
3
jrudolph
^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$

Có lẽ một cách ngắn gọn hơn có thể là:

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

Điều này sau đó có thể được tăng cường lên 1.2.3.4.5. * Hoặc giới hạn chính xác ở X.Y.Z bằng cách sử dụng * hoặc {2} thay vì {0,2}

3
ofaurax

Tôi có một yêu cầu tìm kiếm/khớp các số phiên bản, theo quy ước maven hoặc thậm chí chỉ là một chữ số. Nhưng không có vòng loại trong mọi trường hợp. Điều đó thật đặc biệt, tôi phải mất thời gian sau đó mới nghĩ ra điều này:

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

Điều này đảm bảo phiên bản,

  1. Bắt đầu bằng một chữ số
  2. Có thể có bất kỳ số chữ số
  3. Chỉ các chữ số và '.' được cho phép

Một nhược điểm là phiên bản thậm chí có thể kết thúc bằng '.' Nhưng nó có thể xử lý độ dài không xác định của phiên bản (phiên bản điên nếu bạn muốn gọi nó là phiên bản đó)

Diêm:

  • 1.2.3
  • 1,09,5
  • 3.4.4.5.7.8.8.
  • 23.6.209.234.3

Nếu bạn không hài lòng với '.' kết thúc, có thể bạn có thể kết hợp với logic endswith

3
Shiva

Có vẻ như rất khó để có một regex thực hiện chính xác những gì bạn muốn (tức là chỉ chấp nhận các trường hợp bạn cần và từ chối tất cả người khác trả về một số nhóm cho ba thành phần). Tôi đã thử và nghĩ ra điều này:

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

IMO (Tôi chưa được thử nghiệm rộng rãi) điều này sẽ hoạt động tốt như một trình xác nhận cho đầu vào, nhưng vấn đề là regex này không cung cấp cách lấy các thành phần. Cho rằng bạn vẫn phải chia một khoảng thời gian.

Giải pháp này không phải là tất cả trong một, nhưng hầu hết các lần lập trình đều không cần. Tất nhiên điều này phụ thuộc vào các hạn chế khác mà bạn có thể có trong mã của mình.

2
rslite

Hãy ghi nhớ regrec là tham lam, vì vậy nếu bạn chỉ tìm kiếm trong chuỗi số phiên bản chứ không phải trong một văn bản lớn hơn, hãy sử dụng ^ và $ để đánh dấu bắt đầu và kết thúc chuỗi của bạn. Regrec từ Greg có vẻ hoạt động tốt (chỉ cần thử nhanh trong trình chỉnh sửa của tôi), nhưng tùy thuộc vào thư viện/ngôn ngữ của bạn, phần đầu tiên vẫn có thể khớp với "*" trong các số phiên bản sai. Có lẽ tôi đang thiếu một cái gì đó, vì tôi đã không sử dụng Regapi trong một năm hoặc lâu hơn.

Điều này sẽ đảm bảo bạn chỉ có thể tìm thấy số phiên bản chính xác:

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

chỉnh sửa: thực sự greg đã thêm chúng và thậm chí đã cải thiện giải pháp của mình, tôi quá chậm :)

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

Có khớp chính xác với 6 ví dụ đầu tiên của bạn không và từ chối 4 ví dụ khác

  • nhóm 1: chính hoặc chính.minor hoặc '*'
  • nhóm 2 nếu tồn tại: nhỏ hoặc *
  • nhóm 3 nếu tồn tại: *

Bạn có thể xóa '(? Ms)'
[.__.] Tôi đã sử dụng nó để biểu thị cho biểu thức chính quy này được áp dụng trên nhiều dòng thông qua QuickRex

2
VonC

Chỉ định các yếu tố 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

Điều này khớp với 1.2.3. * Quá

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

Tôi sẽ đề xuất những người kém thanh lịch:

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

2
Victor

Tôi đảm nhận việc này, như một bài tập tốt - vparse , trong đó có nguồn nhỏ , với một chức năng đơn giản:

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

Thêm một giải pháp:

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