<?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.assertions.php',
    1 => '断言',
    2 => '断言',
  ),
  'up' => 
  array (
    0 => 'reference.pcre.pattern.syntax.php',
    1 => 'PCRE 正则语法',
  ),
  'prev' => 
  array (
    0 => 'regexp.reference.back-references.php',
    1 => '后向引用',
  ),
  'next' => 
  array (
    0 => 'regexp.reference.onlyonce.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.assertions" class="section">
  <h2 class="title">断言</h2>
  <p class="para">
  一个断言就是一个对当前匹配位置之前或之后的字符的测试，
  它不会实际消耗任何字符。简单的断言代码有\b、\B、 \A、 \Z、\z、 ^、$ 等，在
   <a href="regexp.reference.escape.php" class="link">转义序列(反斜线)</a> 中有描述。
  更加复杂的断言以子组的方式编码。 它有两种类型：
  <em>前瞻断言</em>(从当前位置向前测试)和<em>后瞻断言</em>(从当前位置向后测试)。
  </p>
  <p class="para">
  一个断言子组的匹配还是通过普通方式进行的，
  不同在于它不会导致当前的匹配点发生改变。
  <em>前瞻断言</em>中的正面断言(断言此匹配为真)以 ”(?=” 开始，消极断言以 ”(?!” 开头。比如，

   <code class="literal">\w+(?=;)</code>

   匹配一个单词紧跟着一个分号但是匹配结果不会包含分号，

  <code class="literal">foo(?!bar)</code>

   匹配所有后面没有紧跟 ”bar” 的 ”foo” 字符串。
  注意一个类似的模式

   <code class="literal">(?!foo)bar</code>

  它不能用于查找之前出现所有不是 ”foo” 的 ”bar” 匹配，
  它会查找到任意的 ”bar” 出现的情况，
  因为 (?!foo) 这个断言在接下来三个字符时 ”bar” 的时候是永远都 <strong><code><a href="reserved.constants.php#constant.true">true</a></code></strong> 的。
  前瞻断言需要达到的就是这样的效果。
  </p>
  <p class="para">
  <em>后瞻断言</em>中的正面断言以”(?&lt;=”开始, 消极断言以”(?&lt;!”开始。比如，

  <code class="literal">(?&lt;!foo)bar</code>

   用于查找任何前面不是 ”foo” 的 ”bar”。
  后瞻断言的内容被严格限制为只能用于匹配定长字符串。但是，如果有多个可选分支，
  它们不需要拥有相同的长度。比如

   <code class="literal">(?&lt;=bullock|donkey)</code>

   是允许的，
  但是

   <code class="literal">(?&lt;!dogs?|cats?)</code>

   将会引发一个编译期的错误。在最上级分支可以匹配不同长度的字符串是允许的。
  相比较于 perl 5.005 而言，它会要求多个分支使用相同长度的字符串匹配。

  <code class="literal">(?&lt;=ab(c|de))</code>

   这样的断言是不允许的，
  因为它单个的顶级分支可以匹配两个不同的长度，
  但是它可以接受使用两个顶级分支的写法

   <code class="literal">(?&lt;=abc|abde)</code>

   这样的断言实现，
  对于每个可选分支，暂时将当前位置移动到尝试匹配的当前位置之前的固定宽度处。
  如果在当前没有足够的字符就视为匹配失败。后瞻断言与一次性子组结合使用可以用来匹配字符串结尾；
  一个例子就是在一次性子组上给出字符串结尾。
  </p>
  <p class="para">
  多个断言(任意顺序)可以同时出现。
  比如

   <code class="literal">(?&lt;=\d{3})(?&lt;!999)foo</code>

   匹配前面有三个数字但不是 ”999” 的字符串 ”foo”。注意，
  每个断言独立应用到对目标字符串该点的匹配。 首先它会检查前面的三位都是数字，
  然后检查这三位不是 ”999”。
  这个模式不能匹配 ”foo” 前面有三位数字然后紧跟 3 位非 999 共 6 个字符的字符串，比如，
  它不匹配 ”123abcfoo”。
  匹配 ”123abcfoo” 这个字符串的模式可以是

   <code class="literal">(?&lt;=\d{3}…)(?&lt;!999)foo</code>。
  </p>
  <p class="para">
  这种情况下，第一个断言查看(当前匹配点)前面的 6 个字符，检查前三个是数字，
  然后第二个断言检查(当前匹配点)前三个字符不是 ”999”。
  </p>
  <p class="para">
  断言可以以任意复杂度嵌套。
  比如

   <code class="literal">(?&lt;=(?&lt;!foo)bar)baz</code>

   匹配前面有 ”bar” 但是 ”bar” 前面没有 ”foo” 的 ”baz”。
  另外一个模式

   <code class="literal">(?&lt;=\d{3}...(?&lt;!999))foo</code>

   则匹配前面有三个数字字符紧跟 3 个不是 999 的任意字符的 ”foo”。
  </p>
  <p class="para">
  断言子组时非捕获子组，并且不能用量词修饰，
  因为对同一件事做多次断言是没有意义的.如果所有的断言都包含一个捕获子组，
  那么为了在整个模式中捕获子组计数的目的，它们都会被计算在内。然而，
  子字符串的捕获仅可以用于正面断言，因为对于消极的断言是没有意义的。
  </p>
  <p class="para">
  将断言计算在内，可以拥有的最大子组数量是  200 个。
  </p>
 </div><?php manual_footer($setup); ?>