RegEx强制检索空的命名组

时间:2017-07-10 23:58:38

标签: php regex conditional-regex

我实现了一个解析一些URI模式的路由器类,以便正确地路由到控制器。

假设遵循简单的测试用例和我的期望

~/erlang_programs/my_gun$ gmake run
gmake[1]: Entering directory '/Users/7stud/erlang_programs/my_gun/deps/gun'
gmake[2]: Entering directory '/Users/7stud/erlang_programs/my_gun/deps/cowlib'
gmake[2]: Leaving directory '/Users/7stud/erlang_programs/my_gun/deps/cowlib'
gmake[2]: Entering directory '/Users/7stud/erlang_programs/my_gun/deps/ranch'
gmake[2]: Leaving directory '/Users/7stud/erlang_programs/my_gun/deps/ranch'
 GEN    rebar.config
gmake[1]: Leaving directory '/Users/7stud/erlang_programs/my_gun/deps/gun'
 DEPEND my_gun.d
 ERLC   my.erl
 APP    my_gun
===> Starting relx build process ...
===> Resolving OTP Applications from directories:
          /Users/7stud/erlang_programs/my_gun/ebin
          /Users/7stud/erlang_programs/my_gun/deps
          /Users/7stud/.evm/erlang_versions/otp_src_19.2/lib/erlang/lib
          /Users/7stud/erlang_programs/my_gun/apps
          /Users/7stud/erlang_programs/my_gun/_rel
===> Resolved my_gun_release-1
===> rendering builtin_hook_status hook to "/Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/bin/hooks/builtin/status"
===> Including Erts from /Users/7stud/.evm/erlang_versions/otp_src_19.2/lib/erlang
===> release successfully created!
===> tarball /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/my_gun_release-1.tar.gz successfully created!
Exec: /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/erts-8.2/bin/erlexec -boot /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/releases/1/my_gun_release -mode embedded -boot_var ERTS_LIB_DIR /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/lib -config /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/releases/1/sys.config -args_file /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release/releases/1/vm.args -pa -- console
Root: /Users/7stud/erlang_programs/my_gun/_rel/my_gun_release
/Users/7stud/erlang_programs/my_gun/_rel/my_gun_release
heart_beat_kill_pid = 38883
Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]


=PROGRESS REPORT==== 10-Jul-2017::18:04:38 ===
          supervisor: {local,sasl_safe_sup}
             started: [{pid,<0.353.0>},
                       {id,alarm_handler},
                       {mfargs,{alarm_handler,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 10-Jul-2017::18:04:38 ===
          supervisor: {local,sasl_sup}
             started: [{pid,<0.352.0>},
                       {id,sasl_safe_sup},
                       {mfargs,
                           {supervisor,start_link,
                               [{local,sasl_safe_sup},sasl,safe]}},
                       {restart_type,permanent},
                       {shutdown,infinity},
                       {child_type,supervisor}]

=PROGRESS REPORT==== 10-Jul-2017::18:04:38 ===
          supervisor: {local,sasl_sup}
             started: [{pid,<0.354.0>},
                       {id,release_handler},
                       {mfargs,{release_handler,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 10-Jul-2017::18:04:38 ===
         application: sasl
          started_at: 'my_gun@127.0.0.1'

=PROGRESS REPORT==== 10-Jul-2017::18:04:38 ===
          supervisor: {local,runtime_tools_sup}
             started: [{pid,<0.360.0>},
                       {id,ttb_autostart},
                       {mfargs,{ttb_autostart,start_link,[]}},
                       {restart_type,temporary},
                       {shutdown,3000},
                       {child_type,worker}]

=PROGRESS REPORT==== 10-Jul-2017::18:04:38 ===
         application: runtime_tools
          started_at: 'my_gun@127.0.0.1'
Eshell V8.2  (abort with ^G)

(my_gun@127.0.0.1)1> my:ws().

=PROGRESS REPORT==== 10-Jul-2017::18:04:41 ===
          supervisor: {local,inet_gethost_native_sup}
             started: [{pid,<0.367.0>},{mfa,{inet_gethost_native,init,[[]]}}]

=PROGRESS REPORT==== 10-Jul-2017::18:04:41 ===
          supervisor: {local,kernel_safe_sup}
             started: [{pid,<0.366.0>},
                       {id,inet_gethost_native_sup},
                       {mfargs,{inet_gethost_native,start_link,[]}},
                       {restart_type,temporary},
                       {shutdown,1000},
                       {child_type,worker}]
Upgraded <0.365.0>. Success!
Headers:
[{<<"connection">>,<<"Upgrade">>},
 {<<"date">>,<<"Tue, 11 Jul 2017 00:04:40 GMT">>},
 {<<"sec-websocket-accept">>,<<"pYv8QeeJfzQgaS/x8flZHyrIexk=">>},
 {<<"server">>,<<"Cowboy">>},
 {<<"upgrade">>,<<"websocket">>}]
Server received: It's raining!
ok

(my_gun@127.0.0.1)2> 

重要的是将案例1和案例2与可选的尾部斜杠相匹配。两者都应该返回一个空的ID(我不确定它是否可以使用RegEx,我的胆量也是如此)。但是如果存在尾随ID,则案例3到6应该匹配。第7例是假的。

我使用以下脚本测试我的RegEx

/test                              -> should match with ID ""
/test/                             -> should match with ID ""
/test/some-id                      -> should match with ID "some-id"
/test/some-id/                     -> should match with ID "some-id/"
/test/some-id/trailing-id-data     -> should match with ID "some-id/trailing-id-data"
/test/some-id/trailing-id-data/    -> should match with ID "some-id/trailing-id-data/"
/test-someid                       -> should not match

首先,我没有期待一个空ID我尝试了几个RegEx,并指定以下一个工作

<?php
$pattern = '...';
$values = [
  '/test',
  '/test/',
  '/test/some-id',
  '/test/some-id/',
  '/test/some-id/trailing-id-data',
  '/test/some-id/trailing-id-data/',
  '/test-some-id'
];
foreach ( $values as $value )
{
  $matches = [];
  var_export( ( bool ) preg_match( $pattern, $value, $matches ) );
  echo "\n";
  var_export( $matches );
  echo "\n\n";
}

现在排在第二位,我正在努力检索空ID。

一般是否可能,如果可能,怎么样?

2 个答案:

答案 0 :(得分:2)

此模式将根据需要准确匹配您的字符串:

模式:~^/test(?:$|/)\K.*~仅需81步(与Marcos&#39;模式@ 114步相比)

这将匹配/test,如果有任何字符要跟随,则必须以/开头,然后匹配零个或多个字符。 \K表示&#34;从此点开始完全匹配&#34;,因此您可以避免使用捕获组,只访问preg_match()生成的输出数组中的完整字符串匹配元素。

Pattern Demo

PHP代码:(PHP Demo

$values = [
  '/test',
  '/test/',
  '/test/some-id',
  '/test/some-id/',
  '/test/some-id/trailing-id-data',
  '/test/some-id/trailing-id-data/',
  '/test-some-id'
];
foreach($values as $v){
    echo "$v -> ";
    var_export(preg_match("~^/test(?:$|/)\K.*~",$v,$out)?$out:'failed');
    echo "\n";
}

输出:

/test -> array (0 => '')
/test/ -> array (0 => '')
/test/some-id -> array (0 => 'some-id')
/test/some-id/ -> array (0 => 'some-id/')
/test/some-id/trailing-id-data -> array (0 => 'some-id/trailing-id-data')
/test/some-id/trailing-id-data/ -> array (0 => 'some-id/trailing-id-data/')
/test-some-id -> 'failed'

答案 1 :(得分:0)

鉴于您的测试用例,您可以使用类似的内容(请参阅online):

^\/test(?:\/?$|\/(?:(?<id>.*))$)

诀窍是使用线锚$和交替|,所以在(\/?$|\/...中它会匹配前面带有可选斜杠的行尾或匹配模式的另一面

我还使用非捕获组(?:)来防止使用不需要的匹配来填充数组。

最后,我同意@ArtisticPhoenix,也许有一种比使用Regex更好的解释路线的方法,特别是因为这么小的要求变成了一个相当复杂的表达。像MINI之类的东西可能会给你一些启发。