<?php function acceptOne($a) {}; $words = ['ACCESSIBLE', 'ACTION', 'AFTER', 'AGAINST', 'AGGREGATE', 'ALGORITHM', 'ALL', 'ALTER', 'ANALYSE', 'ANALYZE', 'AS', 'ASC', 'AUTOCOMMIT', 'AUTO_INCREMENT', 'BACKUP', 'BEGIN', 'BETWEEN', 'BINLOG', 'BOTH', 'CASCADE', 'CASE', 'CHANGE', 'CHANGED', 'CHARACTER', 'CHARSET', 'CHECK', 'CHECKSUM', 'COLLATE', 'COLLATION', 'COLUMN', 'COLUMNS', 'COMMENT', 'COMMIT', 'COMMITTED', 'COMPRESSED', 'CONCURRENT', 'CONSTRAINT', 'CONTAINS', 'CONVERT', 'CREATE', 'CROSS', 'CURRENT', 'CURRENT_TIMESTAMP', 'DATABASE', 'DATABASES', 'DAY', 'DAY_HOUR', 'DAY_MINUTE', 'DAY_SECOND', 'DEFAULT', 'DEFINER', 'DELAYED', 'DELETE', 'DESC', 'DESCRIBE', 'DETERMINISTIC', 'DISTINCT', 'DISTINCTROW', 'DIV', 'DO', 'DUMPFILE', 'DUPLICATE', 'DYNAMIC', 'ELSE', 'ENCLOSED', 'END', 'ENGINE', 'ENGINES', 'ENGINE_TYPE', 'ESCAPE', 'ESCAPED', 'EVENTS', 'EXEC', 'EXECUTE', 'EXISTS', 'EXPLAIN', 'EXTENDED', 'FAST', 'FETCH', 'FIELDS', 'FILE', 'FILTER', 'FIRST', 'FIXED', 'FLUSH', 'FOLLOWING', 'FOR', 'FORCE', 'FOREIGN', 'FULL', 'FULLTEXT', 'FUNCTION', 'GLOBAL', 'GRANT', 'GRANTS', 'GROUP', 'GROUPS', 'HEAP', 'HIGH_PRIORITY', 'HOSTS', 'HOUR', 'HOUR_MINUTE', 'HOUR_SECOND', 'IDENTIFIED', 'IF', 'IFNULL', 'IGNORE', 'IN', 'INDEX', 'INDEXES', 'INFILE', 'INSERT', 'INSERT_ID', 'INSERT_METHOD', 'INTERVAL', 'INTO', 'INVOKER', 'IS', 'ISOLATION', 'KEY', 'KEYS', 'KILL', 'LAST_INSERT_ID', 'LEADING', 'LEVEL', 'LIKE', 'LINEAR', 'LINES', 'LOAD', 'LOCAL', 'LOCK', 'LOCKS', 'LOGS', 'LOW_PRIORITY', 'MARIA', 'MASTER', 'MASTER_CONNECT_RETRY', 'MASTER_HOST', 'MASTER_LOG_FILE', 'MATCH', 'MAX_CONNECTIONS_PER_HOUR', 'MAX_QUERIES_PER_HOUR', 'MAX_ROWS', 'MAX_UPDATES_PER_HOUR', 'MAX_USER_CONNECTIONS', 'MEDIUM', 'MERGE', 'MINUTE', 'MINUTE_SECOND', 'MIN_ROWS', 'MODE', 'MONTH', 'MRG_MYISAM', 'MYISAM', 'NAMES', 'NATURAL', 'NOT', 'NULL', 'OFFSET', 'ON', 'OPEN', 'OPTIMIZE', 'OPTION', 'OPTIONALLY', 'OUTFILE', 'OVER', 'PACK_KEYS', 'PAGE', 'PARTIAL', 'PARTITION', 'PARTITIONS', 'PASSWORD', 'PRECEDING', 'PRIMARY', 'PRIVILEGES', 'PROCEDURE', 'PROCESS', 'PROCESSLIST', 'PURGE', 'QUICK', 'RAID0', 'RAID_CHUNKS', 'RAID_CHUNKSIZE', 'RAID_TYPE', 'RANGE', 'READ', 'READ_ONLY', 'READ_WRITE', 'RECURSIVE', 'REFERENCES', 'REGEXP', 'RELOAD', 'RENAME', 'REPAIR', 'REPEATABLE', 'REPLACE', 'REPLICATION', 'RESET', 'RESTORE', 'RESTRICT', 'RETURN', 'RETURNS', 'REVOKE', 'RLIKE', 'ROLLBACK', 'ROW', 'ROWS', 'ROW_FORMAT', 'SECOND', 'SECURITY', 'SEPARATOR', 'SERIALIZABLE', 'SESSION', 'SET', 'SHARE', 'SHOW', 'SHUTDOWN', 'SLAVE', 'SONAME', 'SOUNDS', 'SQL', 'SQL_AUTO_IS_NULL', 'SQL_BIG_RESULT', 'SQL_BIG_SELECTS', 'SQL_BIG_TABLES', 'SQL_BUFFER_RESULT', 'SQL_CACHE', 'SQL_CALC_FOUND_ROWS', 'SQL_LOG_BIN', 'SQL_LOG_OFF', 'SQL_LOG_UPDATE', 'SQL_LOW_PRIORITY_UPDATES', 'SQL_MAX_JOIN_SIZE', 'SQL_NO_CACHE', 'SQL_QUOTE_SHOW_CREATE', 'SQL_SAFE_UPDATES', 'SQL_SELECT_LIMIT', 'SQL_SLAVE_SKIP_COUNTER', 'SQL_SMALL_RESULT', 'SQL_WARNINGS', 'START', 'STARTING', 'STATUS', 'STOP', 'STORAGE', 'STRAIGHT_JOIN', 'STRING', 'STRIPED', 'SUPER', 'TABLE', 'TABLES', 'TEMPORARY', 'TERMINATED', 'THEN', 'TIES', 'TO', 'TRAILING', 'TRANSACTIONAL', 'TRUE', 'TRUNCATE', 'TYPE', 'TYPES', 'UNBOUNDED', 'UNCOMMITTED', 'UNIQUE', 'UNLOCK', 'UNSIGNED', 'USAGE', 'USE', 'USING', 'VARIABLES', 'VIEW', 'WHEN', 'WITH', 'WORK', 'WRITE', 'YEAR_MONTH']; $regexDummy = '/' . makeRegexFromListDummy($words) . '/'; $regexOptimized = '/' . makeRegexFromListOptimized($words) . '/'; $regexDummyWithS = '/' . makeRegexFromListDummy($words) . '/S'; var_dump($regexDummy); var_dump($regexOptimized); $testStr = 'BLOB'; $benchFx = function (string $msg, \Closure $fx) { $times = []; for ($i = 0; $i < 100; $i++) { $t = microtime(true); $fx(); $t = microtime(true) - $t; $times[] = $t; } $bestTime = min($times); echo $msg . ': ' . round($bestTime * 1000, 2) . " ms\n"; }; $benchFx('dummy', function () { global $regexDummy, $testStr; for ($i = 0; $i < 5_000; $i++) { preg_match($regexDummy, $testStr . $i, $matches); acceptOne($matches); } }); $benchFx('optimized', function () { global $regexOptimized, $testStr; for ($i = 0; $i < 5_000; $i++) { preg_match($regexOptimized, $testStr . $i, $matches); acceptOne($matches); } }); $benchFx('dummy /w S', function () { global $regexDummyWithS, $testStr; for ($i = 0; $i < 5_000; $i++) { preg_match($regexDummyWithS, $testStr . $i, $matches); acceptOne($matches); } }); function makeRegexFromListDummy(array $values): string { // sort list by alphabet and from longest word to shortest usort($values, static function (string $a, string $b) { return str_starts_with($a, $b) || str_starts_with($b, $a) ? strlen($b) <=> strlen($a) : $a <=> $b; }); $regex = '(?>'; foreach ($values as $v) { if ($regex !== '(?>') { $regex .= '|'; } $regex .= preg_quote($v, '/'); } return $regex . ')'; } function makeRegexFromListOptimized(array $values, bool $sorted = false): string { // sort list by alphabet and from longest word to shortest if (! $sorted) { usort($values, static function (string $a, string $b) { return str_starts_with($a, $b) || str_starts_with($b, $a) ? strlen($b) <=> strlen($a) : $a <=> $b; }); } /** @var array<int|string, list<string>> $valuesBySharedPrefix */ $valuesBySharedPrefix = []; $items = []; $prefix = null; foreach ($values as $v) { if ($prefix !== null && ! str_starts_with($v, substr($prefix, 0, 1))) { $valuesBySharedPrefix[$prefix] = $items; $items = []; $prefix = null; } $items[] = $v; if ($prefix === null) { $prefix = $v; } else { while (! str_starts_with($v, $prefix)) { $prefix = substr($prefix, 0, -1); } } } if ($items !== []) { $valuesBySharedPrefix[$prefix] = $items; $items = []; $prefix = null; } $regex = '(?>'; foreach ($valuesBySharedPrefix as $prefix => $items) { if ($regex !== '(?>') { $regex .= '|'; } if (is_int($prefix)) { $prefix = (string) $prefix; } $regex .= preg_quote($prefix, '/'); $regex .= count($items) === 1 ? preg_quote(substr(reset($items), strlen($prefix)), '/') : makeRegexFromListOptimized(array_map(static fn ($v) => substr($v, strlen($prefix)), $items), true); } return $regex . ')'; }
You have javascript disabled. You will not be able to edit any code.