regexp - ¿Cómo extraer dos dígitos consecutivos de un campo de texto en MySQL?
regexp mysql php (6)
Tengo una base de datos MySQL y tengo una consulta como:
SELECT `id`, `originaltext` FROM `source` WHERE `originaltext` regexp ''[0-9][0-9]''
Esto detecta todos los textos originales que tienen números con 2 dígitos.
Necesito MySQL para devolver esos números como un campo , por lo que puedo manipularlos más.
Idealmente, si puedo agregar criterios adicionales que deberían ser> 20 sería genial, pero también puedo hacerlo por separado.
Estoy teniendo el mismo problema, y esta es la solución que encontré (pero no funcionará en todos los casos):
- usa
LOCATE()
para encontrar el principio y el final de la cadena que deseas unir - use
MID()
para extraer la subcadena entre ... - Mantenga la expresión regular para que coincida solo con las filas en las que seguramente encontrará una coincidencia.
No hay ninguna sintaxis en MySQL para extraer texto usando expresiones regulares. Puede usar el REGEXP para identificar las filas que contienen dos dígitos consecutivos, pero para extraerlos debe usar las funciones normales de manipulación de cadenas, lo cual es muy difícil en este caso.
Alternativas:
- Seleccione el valor completo de la base de datos y luego use una expresión regular en el cliente.
- Use una base de datos diferente que tenga un mejor soporte para el estándar SQL (puede que no sea una opción, lo sé). Luego puede usar esto:
SUBSTRING(originaltext from ''%#[0-9]{2}#%'' for ''#'')
.
Sé que ha pasado bastante tiempo desde que se hizo esta pregunta, pero me encontré con ella y pensé que sería un buen desafío para mi sustituto de expresiones regulares personalizado. Consulte esta publicación en el blog .
... Y la buena noticia es que sí, aunque debe llamarse varias veces. Vea esta demostración de rextester en línea , que muestra el funcionamiento que llegó al SQL a continuación.
SELECT reg_replace(
reg_replace(
reg_replace(
reg_replace(
reg_replace(
reg_replace(
reg_replace(txt,
''[^0-9]+'',
'','',
TRUE,
1, -- Min match length
0 -- No max match length
),
''([0-9]{3,}|,[0-9],)'',
'''',
TRUE,
1, -- Min match length
0 -- No max match length
),
''^[0-9],'',
'''',
TRUE,
1, -- Min match length
0 -- No max match length
),
'',[0-9]$'',
'''',
TRUE,
1, -- Min match length
0 -- No max match length
),
'',{2,}'',
'','',
TRUE,
1, -- Min match length
0 -- No max match length
),
''^,'',
'''',
TRUE,
1, -- Min match length
0 -- No max match length
),
'',$'',
'''',
TRUE,
1, -- Min match length
0 -- No max match length
) AS `csv`
FROM tbl;
Si desea un poder de expresión más regular en su base de datos, puede considerar usar LIB_MYSQLUDF_PREG . Esta es una biblioteca de código abierto de funciones de usuario MySQL que importa la biblioteca PCRE. LIB_MYSQLUDF_PREG se entrega únicamente en formato de código fuente. Para usarlo, necesitarás poder compilarlo e instalarlo en tu servidor MySQL. Instalar esta biblioteca no cambia la compatibilidad con expresiones regulares incorporadas de MySQL de ninguna manera. Simplemente hace disponibles las siguientes funciones adicionales:
PREG_CAPTURE extrae una coincidencia de expresión regular de una cadena. PREG_POSITION devuelve la posición en la que una expresión regular coincide con una cadena. PREG_REPLACE realiza una búsqueda y reemplazo en una cadena. PREG_RLIKE prueba si una expresión regular coincide con una cadena.
Todas estas funciones toman una expresión regular como su primer parámetro. Esta expresión regular debe formatearse como un operador de expresión regular de Perl. Por ejemplo, para probar si Regex coincide con el asunto insensiblemente, usaría el código MySQL PREG_RLIKE (''/ regex / i'', asunto). Esto es similar a las funciones de preg de PHP, que también requieren los delimitadores adicionales // para las expresiones regulares dentro de la cadena de PHP.
Si desea algo más simple, puede modificar esta función para satisfacer mejor sus necesidades.
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''s 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
Si quieres devolver una parte de una cadena:
SELECT id , substring(columnName,(locate(''partOfString'',columnName)),10) from tableName;
Locate()
devolverá la posición inicial de la cadena coincidente que se convierte en la posición de inicio de la Function Substring()
de Function Substring()
Utilicé mi código como un Procedimiento almacenado (Función), funcionará para extraer cualquier número creado a partir de dígitos en un solo bloque. Esta es una parte de mi biblioteca más amplia.
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$$