正则表达式 - 前瞻性贪婪但可选

时间:2015-03-11 14:54:41

标签: php regex

需要正则表达式的帮助,我花了好几个小时尝试各个方向,但我似乎无法弄清楚... 我有类似的固件文件名:

  • sw_smv-e10200_400_800_6.0.5.2-50o - HF157793_770720_50o_2-prod.sig
  • sw_smv-e10200_400_800_6.0.5.2-50o_761649-prod.sig
  • sw_e10200_400_800_6.0.1.8_146o_60ksso_1-prod.bin.sig
  • sw_smv-e10200_400_800_6.0.1.8_164o_600296-prod.sig

我想提取干净的版本号,例如:

  • 6.0.5.2-50o - HF157793(_50o)_2
  • 6.0.5.2-50o
  • 6.0.1.8_146o_60ksso_1
  • 6.0.1.8_164o

这是我到目前为止的正则表达式:

(e10200_400_800_)(.*)(_[0-9]{6})(.*)?-(prod|stdeb)

但这似乎给我带来了麻烦,没有_ [0-9] {6}匹配的ksso并且根本无法返回任何东西...... 如果我加一个?对它来说,即使是在像

这样的懒惰/贪婪玩法时,我也会把它排除在外
(e10200_400_800_)(.*?)(_[0-9]{6})?+(.*?)?-(prod|stdeb)

我也尝试使用前瞻/后视,但无法获得良好的组合......

任何人都有我的解决方案吗?

5 个答案:

答案 0 :(得分:1)

你走了:

([0-9]+\..+?)(?(?=_\d{6})_\d{6}|(_[^_-]+?))(?:_\d{6}|(_.*?))?(?:-prod|-stdeb)

Demo

这是一个令人心碎的事。条件表达式和替代列表是关键。您所需的字符串是所有3个组的总和。

MATCH 1
1.  [22-43] `6.0.5.2-50o--HF157793`
2.  EMPTY
3.  [50-56] `_50o_2`
MATCH 2
1.  [88-99] `6.0.5.2-50o`
2.  EMPTY
3.  EMPTY
MATCH 3
1.  [138-145]   `6.0.1.8`
2.  [145-150]   `_146o`
3.  [150-159]   `_60ksso_1`
MATCH 4
1.  [195-202]   `6.0.1.8`
2.  [202-207]   `_164o`
3.  EMPTY

答案 1 :(得分:1)

这适用于您的样本(?<=_)(\d+\.(?:(?!_\d{6}).)+)(?:_\d{6})?(.*)(?=-(?:prod|stdeb))

该版本是第2组捕获的捕获组1。

Formatted

 (?<= _ )                      # Lookbehind '_'
 (                             # (1 start), Version number  'digit(s) dot plus greedy anything(s)'
      \d+ \.
      (?:
           (?! _ \d{6} )                 # not '_ \d{6}' anywhere
           . 
      )+
 )                             # (1 end)
 (?: _ \d{6} )?                # optional '_666666'
 ( .* )                        # (2), Optional remainder greedy anything(s)
 (?=                           # Lookahead
      -                             # '-'
      (?: prod | stdeb )            # 'prod' or 'stdeb'
 )

输出:

  **  Grp 0 -  ( pos 23 , len 34 ) 
 6.0.5.2-50o--HF157793_770720_50o_2  
  **  Grp 1 -  ( pos 23 , len 21 ) 
 6.0.5.2-50o--HF157793  
  **  Grp 2 -  ( pos 51 , len 6 ) 
 _50o_2  

 --------

  **  Grp 0 -  ( pos 91 , len 18 ) 
 6.0.5.2-50o_761649  
  **  Grp 1 -  ( pos 91 , len 11 ) 
 6.0.5.2-50o  
  **  Grp 2 -  ( pos 109 , len 0 )  EMPTY 

 --------

  **  Grp 0 -  ( pos 139 , len 21 ) 
 6.0.1.8_146o_60ksso_1  
  **  Grp 1 -  ( pos 139 , len 21 ) 
 6.0.1.8_146o_60ksso_1  
  **  Grp 2 -  ( pos 160 , len 0 )  EMPTY 

 --------

  **  Grp 0 -  ( pos 198 , len 19 ) 
 6.0.1.8_164o_600296  
  **  Grp 1 -  ( pos 198 , len 12 ) 
 6.0.1.8_164o  
  **  Grp 2 -  ( pos 217 , len 0 )  EMPTY 

答案 2 :(得分:0)

您的文件名称中可能有点(最重要的部分)? 不过,你可以尝试使用这个

[0-9]\..+(?=-prod|-stdeb)

它适用于您提供https://regex101.com/r/hX8eX4/1

的示例

答案 3 :(得分:0)

这似乎有效:

(([0-9]\..+)(?:(?>_\d{6}))(.*)|([0-9]\..+)(?:(?!\d{6})))(?=-prod|-stdeb)

Demo 在匹配[2] + [3]或[4]

中得到了我想要的结果

感谢您的帮助!

答案 4 :(得分:0)

我认为您正在寻找的工具是conditional group

e10200_400_800_\K\d+(?:\.\d+)+[_-]\d+[a-z](?(?!_\d{6}-)[^.]*(?=-prod|-stdeb))

这是条件:

(?(?!_\d{6}-)[^.]*(?=-prod|-stdeb))

如果字符串中的下一个内容与_\d{6}-不匹配,请继续匹配,直到您到达下一个事件-prod-stdeb的位置。否则,请在此处停止匹配。

DEMO

我还使用了\K,这个可怜人的后卫:

e10200_400_800_\K

这允许我匹配e10200_400_800_前缀以确保匹配从正确的位置开始,但不会在匹配中包含前缀。我本可以使用实际的lookbehind,但\K更整洁,更灵活。

相关问题