/core/src/main/php/text/regex/Pattern.class.php

https://github.com/treuter/xp-framework · PHP · 182 lines · 98 code · 15 blank · 69 comment · 21 complexity · 7a6b78bd150e35c10e11a13ee772c469 MD5 · raw file

  1. <?php
  2. /* This class is part of the XP framework
  3. *
  4. * $Id$
  5. */
  6. uses('text.regex.Matcher');
  7. /**
  8. * Represents a regular expression pattern
  9. *
  10. * @test xp://net.xp_framework.unittest.text.PatternTest
  11. * @see php://preg
  12. * @purpose Regular Expression
  13. */
  14. class Pattern extends Object implements Matcher {
  15. const
  16. CASE_INSENSITIVE = 0x0001,
  17. MULTILINE = 0x0002,
  18. DOTALL = 0x0004,
  19. EXTENDED = 0x0008,
  20. ANCHORED = 0x0010,
  21. DOLLAR_ENDONLY = 0x0020,
  22. ANALYSIS = 0x0040,
  23. UNGREEDY = 0x0080,
  24. UTF8 = 0x0100;
  25. protected static $flags= array(
  26. self::CASE_INSENSITIVE => 'i',
  27. self::MULTILINE => 'm',
  28. self::DOTALL => 's',
  29. self::EXTENDED => 'x',
  30. self::ANCHORED => 'A',
  31. self::DOLLAR_ENDONLY => 'D',
  32. self::ANALYSIS => 'S',
  33. self::UNGREEDY => 'U',
  34. self::UTF8 => 'u',
  35. );
  36. protected
  37. $regex = '',
  38. $utf8 = FALSE;
  39. /**
  40. * Constructor
  41. *
  42. * @param string regex
  43. * @param int flags default 0 bitfield of pattern flags
  44. */
  45. public function __construct($regex, $flags= 0) {
  46. $modifiers= '';
  47. foreach (self::$flags as $bit => $str) {
  48. if ($flags & $bit) $modifiers.= $str;
  49. }
  50. $this->utf8= (bool)($flags & self::UTF8);
  51. $this->regex= '/'.str_replace('/', '\/', $regex).'/'.$modifiers;
  52. }
  53. /**
  54. * Creates a string representation of this object
  55. *
  56. * @return string
  57. */
  58. public function toString() {
  59. return $this->getClassName().'<'.$this->regex.'>';
  60. }
  61. /**
  62. * String cast overloading
  63. *
  64. * @return string
  65. */
  66. public function __toString() {
  67. return $this->regex;
  68. }
  69. /**
  70. * Returns whether a given object is equal to this
  71. *
  72. * @param lang.Generic cmp
  73. * @return bool
  74. */
  75. public function equals($cmp) {
  76. return $cmp instanceof self && $cmp->regex === $this->regex;
  77. }
  78. /**
  79. * Returns a hashcode for this pattern
  80. *
  81. * @return string
  82. */
  83. public function hashCode() {
  84. return 'R'.$this->regex;
  85. }
  86. /**
  87. * Returns whether given input is matched.
  88. *
  89. * @param string input
  90. * @return bool
  91. * @throws lang.FormatException
  92. */
  93. public function matches($input) {
  94. if ($input instanceof String) {
  95. $n= preg_match($this->regex, (string)$input->getBytes($this->utf8 ? 'utf-8' : 'iso-8859-1'));
  96. } else {
  97. $n= preg_match($this->regex, (string)$input);
  98. }
  99. if (FALSE === $n || PREG_NO_ERROR != preg_last_error()) {
  100. $e= new FormatException('Pattern "'.$this->regex.'" matching error');
  101. xp::gc(__FILE__);
  102. throw $e;
  103. }
  104. return $n != 0;
  105. }
  106. /**
  107. * Returns how many times a given input is matched.
  108. *
  109. * @param string input
  110. * @return text.regex.MatchResult
  111. * @throws lang.FormatException
  112. */
  113. public function match($input) {
  114. if ($input instanceof String) {
  115. $n= preg_match_all($this->regex, (string)$input->getBytes($this->utf8 ? 'utf-8' : 'iso-8859-1'), $m, PREG_SET_ORDER);
  116. } else {
  117. $n= preg_match_all($this->regex, (string)$input, $m, PREG_SET_ORDER);
  118. }
  119. if (FALSE === $n || PREG_NO_ERROR != preg_last_error()) {
  120. $e= new FormatException('Pattern "'.$this->regex.'" matching error');
  121. xp::gc(__FILE__);
  122. throw $e;
  123. }
  124. return new MatchResult($n, $m);
  125. }
  126. /**
  127. * Performs a replacement
  128. *
  129. * @param string replacement
  130. * @param string input
  131. * @return string
  132. * @throws lang.FormatException
  133. */
  134. public function replaceWith($replacement, $input) {
  135. if ($input instanceof String) {
  136. $r= preg_replace($this->regex, $replacement, (string)$input->getBytes($this->utf8 ? 'utf-8' : 'iso-8859-1'));
  137. } else {
  138. $r= preg_replace($this->regex, $replacement, (string)$input);
  139. }
  140. if (FALSE === $r || PREG_NO_ERROR != preg_last_error()) {
  141. $e= new FormatException('Pattern "'.$this->regex.'" matching error');
  142. xp::gc(__FILE__);
  143. throw $e;
  144. }
  145. return $r;
  146. }
  147. /**
  148. * Compiles a pattern and returns the object
  149. *
  150. * @param string regex
  151. * @param int flags default 0 bitfield of pattern flags
  152. * @return text.regex.Pattern
  153. * @throws lang.FormatException
  154. */
  155. public static function compile($regex, $flags= 0) {
  156. $self= new self($regex, $flags);
  157. // Compile and test pattern
  158. $n= preg_match($self->regex, '');
  159. if (FALSE === $n || PREG_NO_ERROR != preg_last_error()) {
  160. $e= new FormatException('Pattern "'.$regex.'" not well-formed');
  161. xp::gc(__FILE__);
  162. throw $e;
  163. }
  164. return $self;
  165. }
  166. }
  167. ?>