首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >正则表达式语法中存在问题

正则表达式语法中存在问题
EN

Stack Overflow用户
提问于 2011-07-23 19:44:48
回答 2查看 97关注 0票数 1

我有一个txt文件,其中有很多行,我想要搜索版本,并确定正则表达式适用于在数组中获得像v 1.31.6.7 2008/03/07这样的内容的日期

从许多像这样的txt文件中:

此文件可能包含由Sourcefire,Inc.创建、测试和认证的专有规则( "VRT certified Rules"),以及由Sourcefire和其他第三方以及$Id创建的规则: ddos.rules,v1.31.6.7 2008/03/07 20:53:40 vrtbuild Exp DDOS规则

版本可以不同,如:v 1.48.6.12

像这样的格式

日期也不同

假设我有很多行重复

代码语言:javascript
运行
复制
$Id: ddos.rules,v 1.31.6.7 2008/03/07 20:53:40 vrtbuild Exp

$Id: exploit.rules,v 1.116.6.53 2008/11/18 16:36:27 vrtbuild Exp $

$Id: misc.rules,v 1.77.6.20 2008/10/17 19:36:59 vrtbuild Exp $

$Id: smtp.rules,v 1.77.6.19 2008/10/17 19:37:00 vrtbuild Exp $

$Id: tftp.rules,v 1.28.6.6 2008/07/22 17:59:06 vrtbuild Exp $

$Id: web-iis.rules,v 1.110.6.11 2008/07/22 17:59:06 vrtbuild Exp $

$Id: web-attacks.rules,v 1.23 2005/05/16 22:18:17 mwatchinski Exp $

具有不同的date和v(版本)值

我发现日期的模式是这样的:

代码语言:javascript
运行
复制
^(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$

有人能解释一下吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-07-24 02:05:16

你的约会正则表达式:

^(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$

..。非常有趣。我决定对此进行分析,看看它到底匹配了什么。事实证明,这个正则表达式匹配格式为:DD/MM/YYYY的1900到9999年的所有有效日期。有趣的是,它还正确地匹配了从1597年到9999年的所有有效的闰日。此正则表达式了解每个月的有效天数。它知道5月份有31天,6月份只有30天。它还知道,除了29天的闰年外,2月有28天。在这里,它被分解了,这样它就可以被凡人阅读:

代码语言:javascript
运行
复制
$re_date = '%
    # Match all valid DD/MM/YYYY dates from 1900 to 9999 and
    #   all leap days from year 1597 to 9999.
    ^                           # Anchor to start of string.
    ( # $1:
      (  # $2: Date format alternative 1: (months having 31 days)
        ( 0[1-9]|[12]\d|3[01])  # $3: Day: 01-09,10-19,20-29,30,31
        \/
        (0[13578]|1[02])        # $4: Month: 01,03,05,07,08,10,12
        \/
        ((19|[2-9]\d)\d{2})     # $5,$6: Year: 1900-9999
      )                         # End $2:
    | (  # $7: Date format alternative 2: (months having 30 days)
        (0[1-9]|[12]\d|30)      # $8: Day: 01-09,10-19,20-29,30
        \/
        (0[13456789]|1[012])    # $9: Month: 01,03-09,10-12
        \/
        ((19|[2-9]\d)\d{2})     # $10,$11: Year: 1900-9999
      )                         # End $7:
    | (  # $12: Date format alternative 3: (month having 28 days)
        (0[1-9]|1\d|2[0-8])     # $13: Day 01-09,10-19,20-28
        \/
        02                      # Month: 02
        \/
        ((19|[2-9]\d)\d{2})     # $14,$15: Year: 1900-9999
      )                         # End $12:
    | (  # $16: Date format alternative 3: (leap days)
        29                      # Day: 29
        \/
        02                      # Month: 02
        \/ # Match all valid leap day dates from year 1597 to 9999.
        (                       # $17: Year alt 1 (divisible by 4 but not 100)
          (1[6-9]|[2-9]\d)      # $18: Century part: 16-19,20-99
          ( 0[48]               # $19: Year part: Either 04-08
          | [2468][048]         # or 20,24,28,40,44,48,60,64,68,80,84,88
          | [13579][26]         # or 12,16,32,36,52,56,72,76,92,96,
          )                     # End $19:
        | (                     # or $20: Year alternative 2 (divisible by 400)
            ( 16                # $21: Century part: Either 16
            | [2468][048]       # or 20,24,28,40,44,48,60,64,68,80,84,88
            | [3579][26]        # or 32,36,52,56,72,76,92,96
            )                   # End $21:
            00                  # Year part: 00
          )                     # End $20:
        )                       # End $17:
      )                         # End $16:
    )                           # End $1:
    $                           # Anchor to end of string.
    %x';

为了解决眼前的问题,这里有一个更精确的正则表达式来解决这个问题:

代码语言:javascript
运行
复制
$count = preg_match_all('%
    # Match version/date sub-string
    \b          # Anchor to word boundary.
    (           # $1: Version number.
      [Vv]      # Version identifier (allow V or v).
      [ ]+      # One or more spaces.
      [0-9]+    # Major version number is one or more digits.
      (?:       # Group minor version numbers.
        \.      # Minor versions separated by dot.
        [0-9]+  # Minor version is one or more digits.
      )*        # Zero or more minor versions.
    )           # End $1: Version number.
    [ ]+        # One or more spaces.
    (           # $2: Date.
      [0-9]{4}  # Year is four digits.
      /         # / Separator.
      [0-9]{2}  # Month is two digits.
      /         # / Separator.
      [0-9]{2}  # Day is two digits.
    )           # End $2: Date.
    %x', $text, $matches);
if ($count > 0) {
    $versions = $matches[1];
    $dates    = $matches[2];
    printf("Found %d matches:\n", $count);
    for ($i = 0; $i < $count; ++$i) {
        printf("  Match%3d:  Version: %-15s  Date: %s\n",
            $i + 1, $versions[$i], $dates[$i]);
    }
} else {
    echo("No matches found.\n");
}

注意:在处理这类非平凡的正则表达式时,最好使用'x'自由空格模式编写它们。这允许添加大量的注释和缩进,这使得它更容易阅读。

票数 1
EN

Stack Overflow用户

发布于 2011-07-23 19:47:18

代码语言:javascript
运行
复制
foreach ($lines as $line){
    if (preg_match("|v (.*?) (.*?) |", $line, $match)){
        echo "found version ".$match[1]." date ".$match[2];
    }
}

这就是你想要的吗?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6800122

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档