3v4l.org

run code in 300+ PHP versions simultaneously
<?php $charmap = [ 'NUL' => "\x00", // NULL (U+0000) 'SOH' => "\x01", // START OF HEADING (U+0001) 'STX' => "\x02", // START OF TEXT (U+0002) 'ETX' => "\x03", // END OF TEXT (U+0003) 'EOT' => "\x04", // END OF TRANSMISSION (U+0004) 'ENQ' => "\x05", // ENQUIRY (U+0005) 'HT' => "\x09", // HORIZONTAL TAB (U+0009) 'LF' => "\x0a", // LINE FEED (U+000A) 'VT' => "\x0b", // VERTICAL TAB (U+000B) 'CR' => "\x0d", // CARRIAGE RETURN (U+000D) 'ETB' => "\x17", // END OF TRANSMISSION BLOCK (U+0017) 'SP' => "\x20", // SPACE (U+0020) 'ZWS' => "\xe2\x80\x8b", // ZERO WIDTH SPACE (U+200B) 'MSBS' => "\xf0\x9d\x85\xb7", // MUSICAL SYMBOL BEGIN SLUR (U+1D177) 'MSBP' => "\xf0\x9d\x85\xb9", // MUSICAL SYMBOL BEGIN PHRASE (U+1D179) ]; foreach ($charmap as $k => $v) { define($k, $v); } $strings = [ 'user6003859' => LF . LF . LF . 'a' . SP . 'b'. SP . SP . 'c' . SP . SP . SP . LF . SP . 'd' . SP . SP . SP . SP . 'e' . LF . MSBS . 'f' . MSBS . 'g' . MSBS . MSBS . 'h' . MSBS . MSBS . ZWS . ZWS . MSBP . MSBP . 'i' . MSBP . SP . MSBP . SP . 'j' . LF . LF . LF . LF . LF . 'k' . SP . 'l' . SP . 'm' . SP . 'n' . SP . SP . SP . LF . MSBP . 'o' . MSBP . MSBP . 'p' . LF . LF . LF . LF, 'mickmackusa' => NUL . LF . LF . SOH . LF . CR . LF . VT . ETB . 'a' . SP . 'ab' . CR . LF . HT . HT . CR . CR . LF . 'cà' . SOH . 'ê߀' . NUL . NUL . 'abcbc'. SP . SP . SP . 'd' . LF . LF . HT . CR . LF . ENQ . SP . SP . SP . 'e' . STX . LF . ETX . LF . EOT . LF ]; function display($str, $charmap) { $converter = array_map(function ($i) { return '{'.$i.'}'; }, array_flip($charmap)); $handle = fopen("data:text/plain,$str", 'r'); while ( false !== $line = fgets($handle) ) { echo strtr($line, $converter), PHP_EOL; } fclose($handle); } class Replacements { const FUNC = 0; const REGEX = 1; protected $patterns; protected $replacements; protected $func; protected $typeRegex; public function __construct($arg) { if ( is_array($arg) ) { $this->type = self::REGEX; $this->patterns = []; $this->replacements = []; $this->addPatterns($arg); } elseif ( is_callable($arg) ) { $this->type = self::FUNC; $this->addFunction($arg); } else throw new Exception('invalid argument type'); } protected function addPatterns($replacements) { foreach($replacements as $pattern => $replacement) { $this->patterns[] = $pattern; $this->replacements[] = $replacement; } } protected function addFunction($func) { $this->func = $func; } public function execute($str) { if ( $this->type === self::REGEX ) return preg_replace($this->patterns, $this->replacements, $str); return call_user_func_array($this->func, [&$str]); } }; $original = new Replacements([ '~\R~u' => "\n", '/(?:^((\pZ)+|((?!\n)\pC)+)(?1)*)|((?1)$)|(?:((?2)+|(?3)+)(?=(?2)|(?3)))/um' => '', '/(\pZ+)|((?!\n)\pC)/u' => ' ', '/(^\n+)|(\n+$)|(\n(?=\n{2}))/u' => '' ]); $simple = new Replacements([ '~\A[\pZ\pC]+|[\pZ\pC]+\z~u' => '', # trim the string '~\R~u' => "\n", # normalize newlines '~\pZ+|[^\n\PC]+~u' => ' ', # replace Z and C with space '~^ +| +$| \K +~m' => '', # trim lines, delete consecutive spaces '~\n\n\K\n+~' => '' # removes more than 2 consecutives newlines ]); $optimized = new Replacements([ '~\r\n?|\x0b|\f|\xe2\x80[\xa8\xa9]~S' => "\n", '~ [^\pZ\pC]+ \K \pZ* (?:[^\PC\n]+\pZ*)* (?: (\n) \pZ*+ (?:[^\PC\n]+\pZ*)*+ (?: (\n) [\pZ\pC]* )?+ (?!\z) | [\pZ\pC]+ )? | [\pZ\pC]+ ~Aux' => '$1$2 ', '~ (?:$|(?<=^ ))~m' => '' ]); $func = new Replacements(function (&$str) { $parts = preg_split('~^[\pC\pZ]+|[\pC\pZ]+$|\R(?:[\pC\pZ]*?(\R)[\pC\pZ]*)?~u', $str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); return implode("\n", array_map(function($i) { return trim(preg_replace('~[\pC\pZ]+~u', ' ', $i));}, $parts)); }); // tests $tests = ['original' => $original, 'simple' => $simple, 'function' => $func, 'optimized' => $optimized]; $str = $strings['user6003859'] . $strings['mickmackusa']; $str = str_repeat($str, 10); $res = []; foreach ($tests as $k=>&$test) { $res[$k] = $test->execute($str); } echo 'same result: ', var_dump(count(array_unique($res)) === 1); $names = array_keys($tests); $times = array_fill_keys($names, 0); define('REPETITIONS', 100); for ($i=0; $i < REPETITIONS; $i++) { shuffle($names); foreach ($names as $name) { $start = microtime(true); $tests[$name]->execute($str); $stop = microtime(true); $times[$name] += $stop - $start; } } foreach($times as $k=>$v) { printf("%-12s: %.2es\n", $k, $v/REPETITIONS); } // display($res['optimized'], $charmap);

Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).

VersionSystem time (s)User time (s)Memory (MiB)
7.3.30.0030.04715.06
7.3.20.0650.02315.47
7.3.10.0710.02415.43
7.3.00.0620.03015.47
7.2.160.0070.05615.25
7.2.150.0660.02515.54
7.2.140.0660.04915.67
7.2.130.0770.05015.47
7.2.120.0460.03015.51
7.2.110.0540.04815.41
7.2.100.0530.05315.61
7.2.90.0810.03315.50
7.2.80.0720.03615.42
7.2.70.0700.04015.55
7.2.60.0590.03015.40
7.2.50.0640.02315.59
7.2.40.0520.02915.61
7.2.30.0550.04415.69
7.2.20.0520.03915.51
7.2.10.0570.04715.56
7.2.00.0490.02915.55
7.1.270.0630.03014.25
7.1.260.0580.03614.55
7.1.250.0540.04414.41
7.1.240.0480.05114.13
7.1.230.0540.03714.45
7.1.220.0650.03414.52
7.1.210.0740.03614.29
7.1.200.0600.06614.53
7.1.190.0790.04914.24
7.1.180.0710.04014.27
7.1.170.0630.05414.45
7.1.160.0680.04314.44
7.1.150.0760.03314.41
7.1.140.0710.05014.50
7.1.130.0720.04914.33
7.1.120.0670.03914.44
7.1.110.0430.04815.64
7.1.100.0400.05215.48
7.1.90.0400.05615.75
7.1.80.0430.04315.76
7.1.70.0340.05714.99
7.1.60.0350.05124.01
7.1.50.0480.05523.84
7.1.40.0430.05223.54
7.1.30.0470.05023.51
7.1.20.0380.05723.51
7.1.10.0380.05914.78
7.1.00.0490.07114.98
7.0.330.0670.04514.05
7.0.320.1410.05113.85
7.0.310.0580.05814.11
7.0.300.0630.05214.05
7.0.290.0640.03514.08
7.0.280.0710.04713.61
7.0.270.0570.03413.80
7.0.260.0700.04714.13
7.0.250.0500.06315.32
7.0.240.0480.06615.25
7.0.230.0640.05115.00
7.0.220.0360.04915.29
7.0.210.0660.04314.62
7.0.200.0340.04914.67
7.0.190.0390.04814.69
7.0.180.0370.05614.42
7.0.170.0420.04314.40
7.0.160.0350.05414.43
7.0.150.0350.05214.56
7.0.140.0380.05314.47
7.0.130.0390.05414.63
7.0.120.0420.05214.61
7.0.110.0400.04614.53
7.0.100.0360.05014.61
7.0.90.0360.05314.61
7.0.80.0340.04614.41
7.0.70.0360.05014.47
7.0.60.0340.05114.35
7.0.50.0370.05414.58
7.0.40.0360.05614.60
7.0.30.0450.06614.63
7.0.20.0540.04514.71
7.0.10.0430.04514.69
7.0.00.0460.05514.62
5.6.400.0300.15114.89
5.6.390.0140.15014.71
5.6.380.0220.14814.65

preferences:
47.05 ms | 400 KiB | 5 Q