Soros.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. <?php
  2. /**
  3. * Soros interpreter
  4. *
  5. * @see http://numbertext.org
  6. * @author Pavel Astakhov <pastakhov@yandex.ru>
  7. * @license LGPL/BSD dual license
  8. * @copyright (c) 2009-2010, László Németh
  9. */
  10. class Soros {
  11. private $patterns = array();
  12. private $values = array();
  13. private $begins = array();
  14. private $ends = array();
  15. private $m;
  16. private $m2;
  17. private $c;
  18. private $c2;
  19. private $slash;
  20. private $pipe;
  21. private $func;
  22. private $numbertext = false;
  23. /**
  24. * Constructor.
  25. * @param string $source
  26. */
  27. public function __construct($source) {
  28. $this->m = array(
  29. "\\",
  30. "\"",
  31. ";",
  32. "#");
  33. $this->m2 = array(
  34. "$",
  35. "(",
  36. ")",
  37. "|");
  38. $this->c = array(
  39. json_decode('"\uE000"'),
  40. json_decode('"\uE001"'),
  41. json_decode('"\uE002"'),
  42. json_decode('"\uE003"'),
  43. );
  44. $this->c2 = array(
  45. json_decode('"\uE004"'),
  46. json_decode('"\uE005"'),
  47. json_decode('"\uE006"'),
  48. json_decode('"\uE007"'),
  49. );
  50. $this->slash = array(json_decode('"\uE000"'));
  51. $this->pipe = array(json_decode('"\uE003"'));
  52. $source = self::translate($source, $this->m, $this->c, "\\");
  53. $source = preg_replace("/(#[^\n]*)?(\n|$)/", ";", $source);
  54. if (strpos($source, "__numbertext__") !== false) {
  55. $this->numbertext = true;
  56. $source = str_replace("__numbertext__", "0+(0|[1-9]\\d*) $1\n", $source);
  57. }
  58. foreach (split(";", $source) as $s) {
  59. if ($s != "" && preg_match("/^\\s*(\"[^\"]*\"|[^\\s]*)\\s*(.*[^\\s])?\\s*$/", $s, $sp) > 0) {
  60. $s = self::translate(preg_replace("/\"$/", "", preg_replace("/^\"/", "", $sp[1], 1), 1), $this->c, $this->m, "");
  61. $s = str_replace($this->slash[0], "\\\\", $s);
  62. $s2 = "";
  63. if (isset($sp[2]))
  64. $s2 = preg_replace("/\"$/", "", preg_replace("/^\"/", "", $sp[2], 1), 1);
  65. $s2 = self::translate($s2, $this->m2, $this->c2, "\\");
  66. $s2 = preg_replace("/(\\$\\d|\\))\\|\\$/", "$1||\\$", $s2);
  67. $s2 = self::translate($s2, $this->c, $this->m, "");
  68. $s2 = self::translate($s2, $this->m2, $this->c, "");
  69. $s2 = self::translate($s2, $this->c2, $this->m2, "");
  70. $s2 = preg_replace("/[$]/", "\\$", $s2); // $ -> \$
  71. $s2 = preg_replace("/" . $this->c[0] . "(\\d)/", $this->c[0] . $this->c[1] . "\\$$1" . $this->c[2], $s2); // $n -> $(\n)
  72. $s2 = preg_replace("/\\\\(\\d)/", "\\$$1", $s2); // \[n] -> $[n]
  73. $s2 = preg_replace("/\\n/", "\n", $s2); // \n -> [new line]
  74. $this->patterns[] = "^" . preg_replace("/\\$$/", "", preg_replace("/^\\^/", "", $s, 1), 1) . "$";
  75. $this->begins[] = (mb_substr($s, 0, 1) == "^");
  76. $this->ends[] = (mb_substr($s, -1) == "$");
  77. $this->values[] = $s2;
  78. }
  79. }
  80. $this->func = self::translate("(?:\\|?(?:\\$\\()+)?" . "(\\|?\\$\\(([^\\(\\)]*)\\)\\|?)" . "(?:\\)+\\|?)?", $this->m2, $this->c, "\\");
  81. }
  82. /**
  83. *
  84. * @param string $input
  85. * @return string
  86. */
  87. public function run($input) {
  88. if (!$this->numbertext)
  89. return $this->run3($input, true, true);
  90. return preg_replace("/ +/", " ", trim($this->run3($input, true, true)));
  91. }
  92. /**
  93. *
  94. * @param string $input
  95. * @param string $begin
  96. * @param string $end
  97. * @return string
  98. */
  99. private function run3($input, $begin, $end) {
  100. $count = count($this->patterns);
  101. for ($i = 0; $i < $count; $i++) {
  102. if ((!$begin && $this->begins[$i]) || (!$end && $this->ends[$i]))
  103. continue;
  104. if (!preg_match("/" . $this->patterns[$i] . "/", $input, $m))
  105. continue;
  106. $s = preg_replace("/" . $this->patterns[$i] . "/", $this->values[$i], $m[0]);
  107. preg_match_all("/" . $this->func . "/u", $s, $n, PREG_OFFSET_CAPTURE);
  108. while (count($n[0]) > 0) {
  109. // n.start() n.group() n.start(1) n.group(1) n.start(2) n.group(2)
  110. //MWDebug::log( $n[0][0][1] . "=>" . $n[0][0][0] . ", " . $n[1][0][1] . "=>" . $n[1][0][0] . ", " . $n[2][0][1] . "=>" . $n[2][0][0] );
  111. $b = false;
  112. $e = false;
  113. if (mb_substr($n[1][0][0], 0, 1) == $this->pipe[0] || mb_substr($n[0][0][0], 0, 1) == $this->pipe[0]) {
  114. $b = true;
  115. } elseif ($n[0][0][1] == 0) {
  116. $b = $begin;
  117. }
  118. if (mb_substr($n[1][0][0], -1) == $this->pipe[0] || mb_substr($n[0][0][0], -1) == $this->pipe[0]) {
  119. $e = true;
  120. } elseif ($n[0][0][1] + strlen($n[0][0][0]) == strlen($s))
  121. $e = $end;
  122. $s = substr($s, 0, $n[1][0][1]) . $this->run3($n[2][0][0], $b, $e) . substr($s, $n[1][0][1] + strlen($n[1][0][0]));
  123. preg_match_all("/" . $this->func . "/u", $s, $n, PREG_OFFSET_CAPTURE);
  124. }
  125. return $s;
  126. }
  127. return "";
  128. }
  129. /**
  130. *
  131. * @param string $s
  132. * @param string $chars
  133. * @param string $chars2
  134. * @param string $delim
  135. * @return string
  136. */
  137. private static function translate($s, $chars, $chars2, $delim) {
  138. $count = count($chars);
  139. for ($i = 0; $i < $count; $i++) {
  140. $s = str_replace($delim . $chars[$i], $chars2[$i], $s);
  141. }
  142. return $s;
  143. }
  144. }