Index: src/__phutil_library_map__.php
===================================================================
--- src/__phutil_library_map__.php
+++ src/__phutil_library_map__.php
@@ -355,6 +355,8 @@
     'DifferentialCommitsFieldSpecification' => 'applications/differential/field/specification/DifferentialCommitsFieldSpecification.php',
     'DifferentialConflictsFieldSpecification' => 'applications/differential/field/specification/DifferentialConflictsFieldSpecification.php',
     'DifferentialController' => 'applications/differential/controller/DifferentialController.php',
+    'DifferentialCustomFieldDependsOnParser' => 'applications/differential/field/parser/DifferentialCustomFieldDependsOnParser.php',
+    'DifferentialCustomFieldDependsOnParserTestCase' => 'applications/differential/field/parser/__tests__/DifferentialCustomFieldDependsOnParserTestCase.php',
     'DifferentialCustomFieldNumericIndex' => 'applications/differential/storage/DifferentialCustomFieldNumericIndex.php',
     'DifferentialCustomFieldStorage' => 'applications/differential/storage/DifferentialCustomFieldStorage.php',
     'DifferentialCustomFieldStringIndex' => 'applications/differential/storage/DifferentialCustomFieldStringIndex.php',
@@ -1369,6 +1371,7 @@
     'PhabricatorCustomFieldIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldIndexStorage.php',
     'PhabricatorCustomFieldInterface' => 'infrastructure/customfield/interface/PhabricatorCustomFieldInterface.php',
     'PhabricatorCustomFieldList' => 'infrastructure/customfield/field/PhabricatorCustomFieldList.php',
+    'PhabricatorCustomFieldMonogramParser' => 'infrastructure/customfield/parser/PhabricatorCustomFieldMonogramParser.php',
     'PhabricatorCustomFieldNotAttachedException' => 'infrastructure/customfield/exception/PhabricatorCustomFieldNotAttachedException.php',
     'PhabricatorCustomFieldNotProxyException' => 'infrastructure/customfield/exception/PhabricatorCustomFieldNotProxyException.php',
     'PhabricatorCustomFieldNumericIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldNumericIndexStorage.php',
@@ -2870,6 +2873,8 @@
     'DifferentialCommitsFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialConflictsFieldSpecification' => 'DifferentialFieldSpecification',
     'DifferentialController' => 'PhabricatorController',
+    'DifferentialCustomFieldDependsOnParser' => 'PhabricatorCustomFieldMonogramParser',
+    'DifferentialCustomFieldDependsOnParserTestCase' => 'PhabricatorTestCase',
     'DifferentialCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage',
     'DifferentialCustomFieldStorage' => 'PhabricatorCustomFieldStorage',
     'DifferentialCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage',
@@ -4053,6 +4058,7 @@
     'PhabricatorCustomFieldImplementationIncompleteException' => 'Exception',
     'PhabricatorCustomFieldIndexStorage' => 'PhabricatorLiskDAO',
     'PhabricatorCustomFieldList' => 'Phobject',
+    'PhabricatorCustomFieldMonogramParser' => 'Phobject',
     'PhabricatorCustomFieldNotAttachedException' => 'Exception',
     'PhabricatorCustomFieldNotProxyException' => 'Exception',
     'PhabricatorCustomFieldNumericIndexStorage' => 'PhabricatorCustomFieldIndexStorage',
Index: src/applications/differential/field/parser/DifferentialCustomFieldDependsOnParser.php
===================================================================
--- /dev/null
+++ src/applications/differential/field/parser/DifferentialCustomFieldDependsOnParser.php
@@ -0,0 +1,32 @@
+<?php
+
+final class DifferentialCustomFieldDependsOnParser
+  extends PhabricatorCustomFieldMonogramParser {
+
+  protected function getPrefixes() {
+    return array(
+      'depends on',
+    );
+  }
+
+  protected function getInfixes() {
+    return array(
+      'diff',
+      'diffs',
+      'change',
+      'changes',
+      'rev',
+      'revs',
+      'revision',
+    );
+  }
+
+  protected function getSuffixes() {
+    return array();
+  }
+
+  protected function getMonogramPattern() {
+    return 'D\d+';
+  }
+
+}
Index: src/applications/differential/field/parser/__tests__/DifferentialCustomFieldDependsOnParserTestCase.php
===================================================================
--- /dev/null
+++ src/applications/differential/field/parser/__tests__/DifferentialCustomFieldDependsOnParserTestCase.php
@@ -0,0 +1,64 @@
+<?php
+
+final class DifferentialCustomFieldDependsOnParserTestCase
+  extends PhabricatorTestCase {
+
+  public function testParser() {
+    $map = array(
+      'quack quack quack' => array(),
+      'D123' => array(),
+      'depends on D123' => array(
+        array(
+          'match' => 'depends on D123',
+          'prefix' => 'depends on',
+          'infix' => '',
+          'monograms' => array('D123'),
+          'suffix' => '',
+          'offset' => 0,
+        ),
+      ),
+      'depends on D123.' => array(
+        array(
+          'match' => 'depends on D123',
+          'prefix' => 'depends on',
+          'infix' => '',
+          'monograms' => array('D123'),
+          'suffix' => '',
+          'offset' => 0,
+        ),
+      ),
+      'depends on D123, D124' => array(
+        array(
+          'match' => 'depends on D123, D124',
+          'prefix' => 'depends on',
+          'infix' => '',
+          'monograms' => array('D123', 'D124'),
+          'suffix' => '',
+          'offset' => 0,
+        ),
+      ),
+      'depends on rev D123' => array(
+        array(
+          'match' => 'depends on rev D123',
+          'prefix' => 'depends on',
+          'infix' => 'rev',
+          'monograms' => array('D123'),
+          'suffix' => '',
+          'offset' => 0,
+        ),
+      ),
+      'depends on duck' => array(
+      ),
+      'depends on D123abc' => array(
+      ),
+    );
+
+    foreach ($map as $input => $expect) {
+      $parser = new DifferentialCustomFieldDependsOnParser();
+      $output = $parser->parseCorpus($input);
+
+      $this->assertEqual($expect, $output, $input);
+    }
+  }
+
+}
Index: src/infrastructure/customfield/parser/PhabricatorCustomFieldMonogramParser.php
===================================================================
--- /dev/null
+++ src/infrastructure/customfield/parser/PhabricatorCustomFieldMonogramParser.php
@@ -0,0 +1,71 @@
+<?php
+
+abstract class PhabricatorCustomFieldMonogramParser
+  extends Phobject {
+
+  abstract protected function getPrefixes();
+  abstract protected function getSuffixes();
+  abstract protected function getInfixes();
+  abstract protected function getMonogramPattern();
+
+  public function parseCorpus($corpus) {
+    $prefixes = $this->getPrefixes();
+    $suffixes = $this->getSuffixes();
+    $infixes = $this->getInfixes();
+
+    $prefix_regex = $this->buildRegex($prefixes);
+    $infix_regex = $this->buildRegex($infixes, true);
+    $suffix_regex = $this->buildRegex($suffixes, true, true);
+
+    $monogram_pattern = $this->getMonogramPattern();
+
+    $pattern =
+      '/'.
+      '(?:^|\b)'.
+      $prefix_regex.
+      $infix_regex.
+      '((?:'.$monogram_pattern.'[,\s]*)+)'.
+      $suffix_regex.
+      '(?:$|\b)'.
+      '/i';
+
+    $matches = null;
+    $ok = preg_match_all(
+      $pattern,
+      $corpus,
+      $matches,
+      PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
+
+    if ($ok === false) {
+      throw new Exception(pht('Regular expression "%s" is invalid!', $pattern));
+    }
+
+    $results = array();
+    foreach ($matches as $set) {
+      $results[] = array(
+        'match' => $set[0][0],
+        'prefix' => $set[1][0],
+        'infix' => $set[2][0],
+        'monograms' => array_filter(preg_split('/[,\s]+/', $set[3][0])),
+        'suffix' => $set[4][0],
+        'offset' => $set[0][1],
+      );
+    }
+
+    return $results;
+  }
+
+  private function buildRegex(array $list, $optional = false, $final = false) {
+    $parts = array();
+    foreach ($list as $string) {
+      $parts[] = preg_quote($string, '/');
+    }
+    $parts = implode('|', $parts);
+
+    $maybe_tail = $final ? '' : '\s+';
+    $maybe_optional = $optional ? '?' : '';
+
+    return '(?:('.$parts.')'.$maybe_tail.')'.$maybe_optional;
+  }
+
+}