regular regexp_replace regexp reg mysql regex mysql-udf

mysql - regexp_replace - regexp sql



¿Cómo hacer una expresión regular reemplazar en MySQL? (10)

Tengo una tabla con ~ 500k filas; varchar (255) filename columna UTF8 contiene un nombre de archivo;

Estoy tratando de eliminar varios caracteres extraños del nombre de archivo; pensé que usaría una clase de caracteres: [^a-zA-Z0-9()_ ./-]

Ahora, ¿hay una función en MySQL que te permita reemplazar a través de una expresión regular ? Estoy buscando una funcionalidad similar a la función REEMPLAZAR (); a continuación se muestra un ejemplo simplificado:

SELECT REPLACE(''stackowerflow'', ''ower'', ''over''); Output: "stackoverflow" /* does something like this exist? */ SELECT X_REG_REPLACE(''Stackoverflow'',''/[A-Zf]/'',''-''); Output: "-tackover-low"

Sé de REGEXP/RLIKE , pero solo comprueban si hay una coincidencia, no cuál es la coincidencia.

( Podría hacer un " SELECT pkey_id,filename FROM foo WHERE filename RLIKE ''[^a-zA-Z0-9()_ ./-]'' " desde un script PHP, hacer un preg_replace y luego " UPDATE foo ... WHERE pkey_id=... ", pero eso parece un último recurso lento y feo hack)


Lo puedes hacer ... pero no es muy sensato ... esto es tan atrevido como lo intentaré ... en la medida en que los RegEx completos te ayuden a utilizar Perl o algo similar.

UPDATE db.tbl SET column = CASE WHEN column REGEXP ''[[:<:]]WORD_TO_REPLACE[[:>:]]'' THEN REPLACE(column,''WORD_TO_REPLACE'',''REPLACEMENT'') END WHERE column REGEXP ''[[:<:]]WORD_TO_REPLACE[[:>:]]''



Mi método de fuerza bruta para hacer que esto funcionara era simplemente:

  1. mysqldump -u user -p database table > dump.sql la tabla - mysqldump -u user -p database table > dump.sql
  2. Busque y reemplace un par de patrones - find /path/to/dump.sql -type f -exec sed -i ''s/old_string/new_string/g'' {} /; , Obviamente, hay otras expresiones regulares perl que también podrías realizar en el archivo.
  3. Importe la tabla - mysqlimport -u user -p database table < dump.sql

Si desea asegurarse de que la cadena no se encuentra en ninguna otra parte de su conjunto de datos, ejecute algunas expresiones regulares para asegurarse de que todas se produzcan en un entorno similar. Tampoco es tan difícil crear una copia de seguridad antes de ejecutar una sustitución, en caso de que accidentalmente destruya algo que pierde profundidad de información.


MySQL 8.0+ puede usar REGEXP_REPLACE forma nativa.

12.5.2 Expresiones regulares :

REGEXP_REPLACE (expr, pat, repl [, pos [, ocurrence [, match_type]]])

Reemplaza las apariciones en la cadena expr que coinciden con la expresión regular especificada por el patrón pat con la cadena de reemplazo repl, y devuelve la cadena resultante. Si expr, pat o repl es NULL, el valor de retorno es NULL.

y soporte de expresiones regulares :

Anteriormente, MySQL usaba la biblioteca de expresiones regulares de Henry Spencer para admitir operadores de expresiones regulares (REGEXP, RLIKE).

El soporte de expresiones regulares se ha vuelto a implementar utilizando International Components for Unicode (ICU), que proporciona soporte completo de Unicode y es seguro para multibytes. La función REGEXP_LIKE () realiza una comparación de expresiones regulares a la manera de los operadores REGEXP y RLIKE, que ahora son sinónimos de esa función. Además, las funciones REGEXP_INSTR (), REGEXP_REPLACE () y REGEXP_SUBSTR () están disponibles para encontrar posiciones de coincidencia y realizar la sustitución y extracción de subcadenas, respectivamente.

SELECT REGEXP_REPLACE('''',''[A-Zf]'',''-'',1,0,''c''); -- Output: -tackover-low

Demostración de DBFiddle


No.

Pero si tiene acceso a su servidor, podría usar una función definida por el usuario (UDF) como mysql-udf-regexp .

EDITAR: MySQL 8.0+ puede usar REGEXP_REPLACE de forma nativa. Más en respuesta arriba


Podemos usar la condición IF en la consulta SELECCIONAR como se muestra a continuación:

Supongamos que para cualquier cosa con "ABC", "ABC1", "ABC2", "ABC3", ..., queremos reemplazar con "ABC" y luego usar las condiciones REGEXP e IF () en la consulta SELECT, podemos lograr esto .

Sintaxis:

SELECT IF(column_name REGEXP ''ABC[0-9]$'',''ABC'',column_name) FROM table1 WHERE column_name LIKE ''ABC%'';

Ejemplo:

SELECT IF(''ABC1'' REGEXP ''ABC[0-9]$'',''ABC'',''ABC1'');


Recientemente escribí una función MySQL para reemplazar cadenas usando expresiones regulares. Puedes encontrar mi publicación en la siguiente ubicación:

http://techras.wordpress.com/2011/06/02/regex-replace-for-mysql/

Aquí está el código de función:

DELIMITER $$ CREATE FUNCTION `regex_replace`(pattern VARCHAR(1000),replacement VARCHAR(1000),original VARCHAR(1000)) RETURNS VARCHAR(1000) DETERMINISTIC BEGIN DECLARE temp VARCHAR(1000); DECLARE ch VARCHAR(1); DECLARE i INT; SET i = 1; SET temp = ''''; IF original REGEXP pattern THEN loop_label: LOOP IF i>CHAR_LENGTH(original) THEN LEAVE loop_label; END IF; SET ch = SUBSTRING(original,i,1); IF NOT ch REGEXP pattern THEN SET temp = CONCAT(temp,ch); ELSE SET temp = CONCAT(temp,replacement); END IF; SET i=i+1; END LOOP; ELSE SET temp = original; END IF; RETURN temp; END$$ DELIMITER ;

Ejecución de ejemplo:

mysql> select regex_replace(''[^a-zA-Z0-9/-]'','''',''2my test3_text-to. check // my- sql (regular) ,expressions ._,'');


Resolvemos este problema sin usar expresiones regulares. Esta consulta reemplaza solo la cadena de coincidencia exacta.

update employee set employee_firstname = trim(REPLACE(concat(" ",employee_firstname," "),'' jay '','' abc ''))

Ejemplo:

emp_id employee_firstname

1 jay

2 jay ajay

3 jay

Después de ejecutar el resultado de la consulta:

emp_id employee_firstname

1 abc

2 abc ajay

3 abc


Utilice MariaDB en su lugar. Tiene una funcion

REGEXP_REPLACE(col, regexp, replace)

Ver los documentos de MariaDB y las mejoras de expresiones regulares de PCRE.

Tenga en cuenta que también puede utilizar la agrupación de expresiones regulares (lo encontré muy útil):

SELECT REGEXP_REPLACE("", "(stack)(over)(flow)", ''//2 - //1 - //3'')

devoluciones

over - stack - flow


ACTUALIZACIÓN 2: Se ha proporcionado un conjunto útil de funciones de expresiones regulares que incluye REGEXP_REPLACE en MySQL 8.0. Esto hace que la lectura sea innecesaria a menos que esté limitado a usar una versión anterior.

ACTUALIZACIÓN 1: Ahora he hecho esto en una entrada de blog: http://stevettt.blogspot.co.uk/2018/02/a-mysql-regular-expression-replace.html

Lo siguiente expande la función proporcionada por Rasika Godawatte, pero rastrea todas las subcadenas necesarias en lugar de solo probar caracteres individuales:

-- ------------------------------------------------------------------------------------ -- USAGE -- ------------------------------------------------------------------------------------ -- SELECT reg_replace(<subject>, -- <pattern>, -- <replacement>, -- <greedy>, -- <minMatchLen>, -- <maxMatchLen>); -- where: -- <subject> is the string to look in for doing the replacements -- <pattern> is the regular expression to match against -- <replacement> is the replacement string -- <greedy> is TRUE for greedy matching or FALSE for non-greedy matching -- <minMatchLen> specifies the minimum match length -- <maxMatchLen> specifies the maximum match length -- (minMatchLen and maxMatchLen are used to improve efficiency but are -- optional and can be set to 0 or NULL if not known/required) -- Example: -- SELECT reg_replace(txt, ''^[Tt][^ ]* '', ''a'', TRUE, 2, 0) FROM tbl; DROP FUNCTION IF EXISTS reg_replace; DELIMITER // CREATE FUNCTION reg_replace(subject VARCHAR(21845), pattern VARCHAR(21845), replacement VARCHAR(21845), greedy BOOLEAN, minMatchLen INT, maxMatchLen INT) RETURNS VARCHAR(21845) DETERMINISTIC BEGIN DECLARE result, subStr, usePattern VARCHAR(21845); DECLARE startPos, prevStartPos, startInc, len, lenInc INT; IF subject REGEXP pattern THEN SET result = ''''; -- Sanitize input parameter values SET minMatchLen = IF(minMatchLen < 1, 1, minMatchLen); SET maxMatchLen = IF(maxMatchLen < 1 OR maxMatchLen > CHAR_LENGTH(subject), CHAR_LENGTH(subject), maxMatchLen); -- Set the pattern to use to match an entire string rather than part of a string SET usePattern = IF (LEFT(pattern, 1) = ''^'', pattern, CONCAT(''^'', pattern)); SET usePattern = IF (RIGHT(pattern, 1) = ''$'', usePattern, CONCAT(usePattern, ''$'')); -- Set start position to 1 if pattern starts with ^ or doesn''t end with $. IF LEFT(pattern, 1) = ''^'' OR RIGHT(pattern, 1) <> ''$'' THEN SET startPos = 1, startInc = 1; -- Otherwise (i.e. pattern ends with $ but doesn''t start with ^): Set start pos -- to the min or max match length from the end (depending on "greedy" flag). ELSEIF greedy THEN SET startPos = CHAR_LENGTH(subject) - maxMatchLen + 1, startInc = 1; ELSE SET startPos = CHAR_LENGTH(subject) - minMatchLen + 1, startInc = -1; END IF; WHILE startPos >= 1 AND startPos <= CHAR_LENGTH(subject) AND startPos + minMatchLen - 1 <= CHAR_LENGTH(subject) AND !(LEFT(pattern, 1) = ''^'' AND startPos <> 1) AND !(RIGHT(pattern, 1) = ''$'' AND startPos + maxMatchLen - 1 < CHAR_LENGTH(subject)) DO -- Set start length to maximum if matching greedily or pattern ends with $. -- Otherwise set starting length to the minimum match length. IF greedy OR RIGHT(pattern, 1) = ''$'' THEN SET len = LEAST(CHAR_LENGTH(subject) - startPos + 1, maxMatchLen), lenInc = -1; ELSE SET len = minMatchLen, lenInc = 1; END IF; SET prevStartPos = startPos; lenLoop: WHILE len >= 1 AND len <= maxMatchLen AND startPos + len - 1 <= CHAR_LENGTH(subject) AND !(RIGHT(pattern, 1) = ''$'' AND startPos + len - 1 <> CHAR_LENGTH(subject)) DO SET subStr = SUBSTRING(subject, startPos, len); IF subStr REGEXP usePattern THEN SET result = IF(startInc = 1, CONCAT(result, replacement), CONCAT(replacement, result)); SET startPos = startPos + startInc * len; LEAVE lenLoop; END IF; SET len = len + lenInc; END WHILE; IF (startPos = prevStartPos) THEN SET result = IF(startInc = 1, CONCAT(result, SUBSTRING(subject, startPos, 1)), CONCAT(SUBSTRING(subject, startPos, 1), result)); SET startPos = startPos + startInc; END IF; END WHILE; IF startInc = 1 AND startPos <= CHAR_LENGTH(subject) THEN SET result = CONCAT(result, RIGHT(subject, CHAR_LENGTH(subject) + 1 - startPos)); ELSEIF startInc = -1 AND startPos >= 1 THEN SET result = CONCAT(LEFT(subject, startPos), result); END IF; ELSE SET result = subject; END IF; RETURN result; END// DELIMITER ;

Manifestación

Rextester Demo

Limitaciones

  1. Este método, por supuesto, va a tomar un tiempo cuando la cadena de asunto es grande. Actualización: ahora se han agregado los parámetros de longitud de coincidencia mínima y máxima para mejorar la eficiencia cuando se conocen (cero = desconocido / ilimitado).
  2. No permitirá la sustitución de referencias inversas (por ejemplo, /1 , /2 etc.) para reemplazar los grupos de captura. Si se necesita esta funcionalidad, vea esta respuesta que intenta proporcionar una solución mediante la actualización de la función para permitir una búsqueda y reemplazo secundario dentro de cada coincidencia encontrada (a costa de una mayor complejidad).
  3. Si se usan ^ y / o $ en el patrón, deben estar al principio y al final, respectivamente, por ejemplo, no se admiten patrones como (^start|end$) .
  4. Hay una bandera "codiciosa" para especificar si el emparejamiento general debe ser codicioso o no codicioso. No se admite la combinación de coincidencias codiciosas y perezosas dentro de una sola expresión regular (por ejemplo, a.*?b.* ).

Ejemplos de uso

La función se ha utilizado para responder a las siguientes preguntas de :