Подтвердить что ты не робот

MySQL - Обратный шаблон соответствия в запросе REGEXP

У меня есть база данных MYSQL, и у меня есть запрос как:

SELECT `id`, `originaltext` FROM `source` WHERE `originaltext` regexp '[0-9][0-9]'

Это определяет все исходные тексты, в которых есть цифры с двумя цифрами.

Мне нужно, чтобы mysql возвращал эти числа в поле , поэтому я могу манипулировать ими дальше.

В идеале, если я могу добавить дополнительные критерии, которые должны быть > 20, это было бы здорово, но я тоже могу сделать это отдельно.

4b9b3361

Ответ 1

Если вы хотите увеличить мощность регулярных выражений в своей базе данных, вы можете использовать LIB_MYSQLUDF_PREG. Это библиотека с открытым исходным кодом пользовательских функций MySQL, которая импортирует библиотеку PCRE. LIB_MYSQLUDF_PREG поставляется только в форме исходного кода. Чтобы использовать его, вам нужно будет скомпилировать его и установить на свой сервер MySQL. Установка этой библиотеки не меняет встроенную поддержку регулярных выражений MySQL. Он просто предоставляет следующие дополнительные функции:

PREG_CAPTURE извлекает регулярное выражение из строки. PREG_POSITION возвращает позицию, в которой регулярное выражение соответствует строке. PREG_REPLACE выполняет поиск и замену строки. PREG_RLIKE проверяет соответствие регулярного выражения строке.

Все эти функции принимают регулярное выражение в качестве первого параметра. Это регулярное выражение должно быть отформатировано как оператор регулярного выражения Perl. Например. чтобы проверить, соответствует ли регулярное выражение объекту без учета регистра, вы должны использовать код MySQL PREG_RLIKE ('/regex/i', subject). Это похоже на PHP preg-функции, для которых также требуются дополнительные//разделители для регулярных выражений внутри строки PHP.

Если вам нужно что-то более простое, вы можете изменить эту функцию в соответствии с вашими потребностями.

CREATE FUNCTION REGEXP_EXTRACT(string TEXT, exp TEXT)
-- Extract the first longest string that matches the regular expression
-- If the string is 'ABCD', check all strings and see what matches: 'ABCD', 'ABC', 'AB', 'A', 'BCD', 'BC', 'B', 'CD', 'C', 'D'
-- It not smart enough to handle things like (A)|(BCD) correctly in that it will return the whole string, not just the matching token.

RETURNS TEXT
DETERMINISTIC
BEGIN
  DECLARE s INT DEFAULT 1;
  DECLARE e INT;
  DECLARE adjustStart TINYINT DEFAULT 1;
  DECLARE adjustEnd TINYINT DEFAULT 1;

  -- Because REGEXP matches anywhere in the string, and we only want the part that matches, adjust the expression to add '^' and '$'
  -- Of course, if those are already there, don't add them, but change the method of extraction accordingly.

  IF LEFT(exp, 1) = '^' THEN 
    SET adjustStart = 0;
  ELSE
    SET exp = CONCAT('^', exp);
  END IF;

  IF RIGHT(exp, 1) = '$' THEN
    SET adjustEnd = 0;
  ELSE
    SET exp = CONCAT(exp, '$');
  END IF;

  -- Loop through the string, moving the end pointer back towards the start pointer, then advance the start pointer and repeat
  -- Bail out of the loops early if the original expression started with '^' or ended with '$', since that means the pointers can't move
  WHILE (s <= LENGTH(string)) DO
    SET e = LENGTH(string);
    WHILE (e >= s) DO
      IF SUBSTRING(string, s, e) REGEXP exp THEN
        RETURN SUBSTRING(string, s, e);
      END IF;
      IF adjustEnd THEN
        SET e = e - 1;
      ELSE
        SET e = s - 1; -- ugh, such a hack to end it early
      END IF;
    END WHILE;
    IF adjustStart THEN
      SET s = s + 1;
    ELSE
      SET s = LENGTH(string) + 1; -- ugh, such a hack to end it early
    END IF;
  END WHILE;

  RETURN NULL;

END

Ответ 2

В MySQL нет синтаксиса для извлечения текста с использованием регулярных выражений. Вы можете использовать REGEXP для идентификации строк, содержащих две последовательные цифры, но для их извлечения вы должны использовать обычные функции манипуляции строками, которые в этом случае очень сложны.

Альтернатива:

  • Выберите все значение из базы данных, затем используйте регулярное выражение на клиенте.
  • Используйте другую базу данных, которая лучше поддерживает стандарт SQL (возможно, это не вариант). Затем вы можете использовать это: SUBSTRING(originaltext from '%#[0-9]{2}#%' for '#').

Ответ 3

У меня такая же проблема, и это решение, которое я нашел (но он не будет работать во всех случаях):

  • используйте LOCATE(), чтобы найти начало и конец строки, которую вы не должны соответствовать
  • используйте MID() для извлечения подстроки между...
  • держите регулярное выражение в соответствии только с строками, в которых вы обязательно найдете совпадение.

Ответ 4

Я использовал свой код в качестве хранимой процедуры (функции), должен работать, чтобы извлечь любое число, построенное из цифр в одном блоке. Это часть моей более широкой библиотеки.

DELIMITER $$

--  2013.04 [email protected]
--  FindNumberInText("ab 234 95 cd", TRUE) => 234  
--  FindNumberInText("ab 234 95 cd", FALSE) => 95

DROP FUNCTION IF EXISTS FindNumberInText$$
CREATE FUNCTION FindNumberInText(_input VARCHAR(64), _fromLeft BOOLEAN) RETURNS VARCHAR(32)
BEGIN
  DECLARE _r              VARCHAR(32) DEFAULT '';
  DECLARE _i              INTEGER DEFAULT 1;
  DECLARE _start          INTEGER DEFAULT 0;
  DECLARE _IsCharNumeric  BOOLEAN;

  IF NOT _fromLeft THEN SET _input = REVERSE(_input); END IF;
  _loop: REPEAT
    SET _IsCharNumeric = LOCATE(MID(_input, _i, 1), "0123456789") > 0;
    IF _IsCharNumeric THEN
      IF _start = 0 THEN SET _start  = _i;  END IF;
    ELSE
      IF _start > 0 THEN LEAVE _loop;       END IF;
    END IF;
    SET _i = _i + 1;
  UNTIL _i > length(_input) END REPEAT;

  IF _start > 0 THEN
    SET _r = MID(_input, _start, _i - _start);
    IF NOT _fromLeft THEN SET _r = REVERSE(_r);  END IF;
  END IF;
  RETURN _r;
END$$

Ответ 5

Если вы хотите вернуть часть строки:

SELECT id , substring(columnName,(locate('partOfString',columnName)),10) from tableName;

Locate() вернет начальную позицию совпадающей строки, которая станет исходной позицией Function Substring()