<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/include/shared-manual.inc';
$TOC = array();
$TOC_DEPRECATED = array();
$PARENTS = array();
include_once dirname(__FILE__) ."/toc/reference.pcre.pattern.syntax.inc";
$setup = array (
  'home' => 
  array (
    0 => 'index.php',
    1 => 'PHP Manual',
  ),
  'head' => 
  array (
    0 => 'UTF-8',
    1 => 'zh',
  ),
  'this' => 
  array (
    0 => 'regexp.reference.subpatterns.php',
    1 => '子组(子模式)',
    2 => '子组(子模式)',
  ),
  'up' => 
  array (
    0 => 'reference.pcre.pattern.syntax.php',
    1 => 'PCRE 正则语法',
  ),
  'prev' => 
  array (
    0 => 'regexp.reference.internal-options.php',
    1 => '内部选项设置',
  ),
  'next' => 
  array (
    0 => 'regexp.reference.repetition.php',
    1 => '重复/量词',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'zh',
    'path' => 'reference/pcre/pattern.syntax.xml',
  ),
  'history' => 
  array (
  ),
);
$setup["toc"] = $TOC;
$setup["toc_deprecated"] = $TOC_DEPRECATED;
$setup["parents"] = $PARENTS;
manual_setup($setup);

contributors($setup);

?>
<div id="regexp.reference.subpatterns" class="section">
  <h2 class="title">子组(子模式)</h2>
  <p class="para">
  子组通过圆括号分隔界定，并且它们可以嵌套。
  将一个模式中的一部分标记为子组(子模式)主要是来做两件事情：
  </p>
  <ol type="1">
   <li class="listitem">
    <p class="para">
    将可选分支局部化。比如，模式<code class="literal">cat(arcat|erpillar|)</code>匹配 ”cat”， “cataract”，
    “caterpillar” 中的一个，如果没有圆括号的话，它匹配的则是 ”cataract”，
    “erpillar” 以及空字符串。
    </p>
   </li>
   <li class="listitem">
    <p class="para">
    将子组设定为捕获子组(向上面定义的)。当整个模式匹配后，
    目标字符串中匹配子组的部分将会通过 <span class="function"><strong>pcre_exec()()</strong></span>
     的 <em>ovector</em> 参数回传给调用者。
    左括号从左至右出现的次序就是对应子组的下标(从 1 开始)，
    可以通过这些下标数字来获取捕获子模式匹配结果。
    </p>
   </li>
  </ol>
  <p class="para">
  比如，如果字符串 ”the red king” 使用模式<code class="literal">((red|white)
  (king|queen))</code> 进行匹配，
  模式匹配到的结果是 array(“red king”， ”red king”, “red”, “king”) 的形式，
  其中第 0 个元素是整个模式匹配的结果，后面的三个元素依次为三个子组匹配的结果。
  它们的下标分别为 1， 2， 3。
  </p>
  <p class="para">
  事实上，并不一定同时需要圆括号的两种功能。
  经常我们会需要子组进行分组， 但又不需要(单独的)捕获它们。
  在子组定义的左括号后面紧跟字符串 ”?:” 会使得该子组不被单独捕获，
  并且不会对其后子组序号的计算产生影响。比如, 如果字符串 &quot;the white queen&quot;
  匹配模式 <code class="literal">the ((?:red|white) (king|queen))</code>，
   匹配到的子串是 &quot;white queen&quot; 和 &quot;queen&quot;，
  他们的下标分别是 1 和 2。
   捕获子组的最大序号为 65535。然而由于 libpcre 的配置，我们可能无法编译这么长的
  正则表达式。
  </p>
  <p class="para">
  为了方便简写，如果需要在非捕获子组开始位置设置选项，
  选项字母可以位于 ? 和 : 之间，比如两个模式：
  </p>
  
  <div class="informalexample">
   <div class="example-contents">
<div class="annotation-interactive cdata"><pre>
(?i:saturday|sunday)
(?:(?i)saturday|sunday)
</pre></div>
   </div>

  </div>
  
  <p class="para">
  匹配到了完全相同的字符集。因为可选分支会从左到右尝试每个分支，
  并且选项没有在子模式结束前被重置，
  并且由于选项的设置会穿透对后面的其他分支产生影响，因此，
  上面的模式都会匹配 ”SUNDAY” 以及 ”Saturday”。
  </p>

  <p class="para">
  可以对子组使用 <code class="literal">(?P&lt;name&gt;pattern)</code> 的语法进行命名。
  这个子模式将会在匹配结果中同时以其名称和顺序(数字下标)出现，
  还有两种为子组命名的语法：
  <code class="literal">(?&lt;name&gt;pattern)</code> 和 <code class="literal">(?&#039;name&#039;pattern)</code>。
  </p>

  <p class="para">
  有时需要多个匹配可以在一个正则表达式中选用子组。
  为了让多个子组可以共用一个后向引用数字的问题，
  <code class="literal">(?|</code> 语法允许复制数字。
  考虑下面的正则表达式匹配<code class="literal">Sunday</code>：
  </p>

  <div class="informalexample">
   <div class="example-contents">
<div class="annotation-interactive cdata"><pre>(?:(Sat)ur|(Sun))day</pre></div>
   </div>

  </div>

  <p class="para">
  <code class="literal">Sun</code> 存储在反向引用 2 中，而反向引用 1 为空。匹配
  <code class="literal">Saturday</code> 则 <code class="literal">Sat</code>
  存储在反向引用 1 中，而反向引用 2 不存在。使用 <code class="literal">(?|</code> 修改模式来修复这个问题：
  </p>

  <div class="informalexample">
   <div class="example-contents">
<div class="annotation-interactive cdata"><pre>(?|(Sat)ur|(Sun))day</pre></div>
   </div>

  </div>

  <p class="para">
  使用这个模式，
  <code class="literal">Sun</code> 和 <code class="literal">Sat</code> 都会被存储到后向引用 1 中。
  </p>
 </div><?php manual_footer($setup); ?>