Soros.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  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 = [];
  12. private $values = [];
  13. private $begins = [];
  14. private $ends = [];
  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 = [
  29. "\\",
  30. "\"",
  31. ";",
  32. "#"];
  33. $this->m2 = [
  34. "$",
  35. "(",
  36. ")",
  37. "|"];
  38. $this->c = [
  39. json_decode('"\uE000"'),
  40. json_decode('"\uE001"'),
  41. json_decode('"\uE002"'),
  42. json_decode('"\uE003"'),
  43. ];
  44. $this->c2 = [
  45. json_decode('"\uE004"'),
  46. json_decode('"\uE005"'),
  47. json_decode('"\uE006"'),
  48. json_decode('"\uE007"'),
  49. ];
  50. $this->slash = [json_decode('"\uE000"')];
  51. $this->pipe = [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. $pieces = explode(";", $source);
  59. foreach ($pieces as $s) {
  60. if ($s != "" && preg_match("/^\\s*(\"[^\"]*\"|[^\\s]*)\\s*(.*[^\\s])?\\s*$/", $s, $sp) > 0) {
  61. $s = self::translate(preg_replace("/\"$/", "", preg_replace("/^\"/", "", $sp[1], 1), 1), $this->c, $this->m, "");
  62. $s = str_replace($this->slash[0], "\\\\", $s);
  63. $s2 = "";
  64. if (isset($sp[2]))
  65. $s2 = preg_replace("/\"$/", "", preg_replace("/^\"/", "", $sp[2], 1), 1);
  66. $s2 = self::translate($s2, $this->m2, $this->c2, "\\");
  67. $s2 = preg_replace("/(\\$\\d|\\))\\|\\$/", "$1||\\$", $s2);
  68. $s2 = self::translate($s2, $this->c, $this->m, "");
  69. $s2 = self::translate($s2, $this->m2, $this->c, "");
  70. $s2 = self::translate($s2, $this->c2, $this->m2, "");
  71. $s2 = preg_replace("/[$]/", "\\$", $s2); // $ -> \$
  72. $s2 = preg_replace("/" . $this->c[0] . "(\\d)/", $this->c[0] . $this->c[1] . "\\$$1" . $this->c[2], $s2); // $n -> $(\n)
  73. $s2 = preg_replace("/\\\\(\\d)/", "\\$$1", $s2); // \[n] -> $[n]
  74. $s2 = preg_replace("/\\n/", "\n", $s2); // \n -> [new line]
  75. $this->patterns[] = "^" . preg_replace("/\\$$/", "", preg_replace("/^\\^/", "", $s, 1), 1) . "$";
  76. $this->begins[] = (mb_substr($s, 0, 1) == "^");
  77. $this->ends[] = (mb_substr($s, -1) == "$");
  78. $this->values[] = $s2;
  79. }
  80. }
  81. $this->func = self::translate("(?:\\|?(?:\\$\\()+)?" . "(\\|?\\$\\(([^\\(\\)]*)\\)\\|?)" . "(?:\\)+\\|?)?", $this->m2, $this->c, "\\");
  82. }
  83. /**
  84. *
  85. * @param string $input
  86. * @return string
  87. */
  88. public function run($input) {
  89. if (!$this->numbertext)
  90. return $this->run3($input, true, true);
  91. return preg_replace("/ +/", " ", trim($this->run3($input, true, true)));
  92. }
  93. /**
  94. *
  95. * @param string $input
  96. * @param string $begin
  97. * @param string $end
  98. * @return string
  99. */
  100. private function run3($input, $begin, $end) {
  101. $count = count($this->patterns);
  102. for ($i = 0; $i < $count; $i++) {
  103. if ((!$begin && $this->begins[$i]) || (!$end && $this->ends[$i]))
  104. continue;
  105. if (!preg_match("/" . $this->patterns[$i] . "/", $input, $m))
  106. continue;
  107. $s = preg_replace("/" . $this->patterns[$i] . "/", $this->values[$i], $m[0]);
  108. preg_match_all("/" . $this->func . "/u", $s, $n, PREG_OFFSET_CAPTURE);
  109. while (count($n[0]) > 0) {
  110. // n.start() n.group() n.start(1) n.group(1) n.start(2) n.group(2)
  111. //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] );
  112. $b = false;
  113. $e = false;
  114. if (mb_substr($n[1][0][0], 0, 1) == $this->pipe[0] || mb_substr($n[0][0][0], 0, 1) == $this->pipe[0]) {
  115. $b = true;
  116. } elseif ($n[0][0][1] == 0) {
  117. $b = $begin;
  118. }
  119. if (mb_substr($n[1][0][0], -1) == $this->pipe[0] || mb_substr($n[0][0][0], -1) == $this->pipe[0]) {
  120. $e = true;
  121. } elseif ($n[0][0][1] + strlen($n[0][0][0]) == strlen($s))
  122. $e = $end;
  123. $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]));
  124. preg_match_all("/" . $this->func . "/u", $s, $n, PREG_OFFSET_CAPTURE);
  125. }
  126. return $s;
  127. }
  128. return "";
  129. }
  130. /**
  131. *
  132. * @param string $s
  133. * @param string $chars
  134. * @param string $chars2
  135. * @param string $delim
  136. * @return string
  137. */
  138. private static function translate($s, $chars, $chars2, $delim) {
  139. $count = count($chars);
  140. for ($i = 0; $i < $count; $i++) {
  141. $s = str_replace($delim . $chars[$i], $chars2[$i], $s);
  142. }
  143. return $s;
  144. }
  145. }