Ho un database di grandi dimensioni che contiene record contenenti tag <a>
e vorrei rimuoverli. Ovviamente c'è il metodo in cui creo uno script PHP che seleziona tutto, utilizza strip_tags
e aggiorna il database, ma questo richiede molto tempo. Quindi, come posso farlo con una semplice (o complicata) query MySQL?Qual è l'equivalente della query MySQL di strip_tags di PHP?
risposta
Non credo che ci sia un modo efficiente per farlo solo in MySQL.
MySQL ha una funzione REPLACE()
, ma può sostituire solo stringhe costanti, non modelli. Potresti scrivere una funzione memorizzata MySQL per cercare e sostituire i tag, ma a quel punto probabilmente stai meglio scrivendo uno script PHP per fare il lavoro. Potrebbe non essere piuttosto come veloce, ma probabilmente sarà più veloce da scrivere.
REPLACE()
funziona abbastanza bene.
L'approccio sottile:
REPLACE(REPLACE(node.body,'<p>',''),'</p>','') as `post_content`
... e non così sottile: (Conversione di stringhe in lumache)
LOWER(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(TRIM(node.title), ':', ''), 'é', 'e'), ')', ''), '(', ''), ',', ''), '\\', ''), '\/', ''), '\"', ''), '?', ''), '\'', ''), '&', ''), '!', ''), '.', ''), '–', ''), ' ', '-'), '--', '-'), '--', '-'), '’', '')) as `post_name`
Qui si va:
CREATE FUNCTION `strip_tags`($str text) RETURNS text
BEGIN
DECLARE $start, $end INT DEFAULT 1;
LOOP
SET $start = LOCATE("<", $str, $start);
IF (!$start) THEN RETURN $str; END IF;
SET $end = LOCATE(">", $str, $start);
IF (!$end) THEN SET $end = $start; END IF;
SET $str = INSERT($str, $start, $end - $start + 1, "");
END LOOP;
END;
ho fatto certo rimuove le parentesi aperte non corrispondenti perché sono pericolose, anche se ignora le parentesi di chiusura non appaiate perché sono innocue.
mysql> select strip_tags('<span>hel<b>lo <a href="world">wo<>rld</a> <<x>again<.');
+----------------------------------------------------------------------+
| strip_tags('<span>hel<b>lo <a href="world">wo<>rld</a> <<x>again<.') |
+----------------------------------------------------------------------+
| hello world again. |
+----------------------------------------------------------------------+
1 row in set
non ha funzionato per me, MySQL ha detto: Documentazione # 1064 - Hai un errore nella sintassi SQL, controllare il manuale che corrisponde alla versione del server MySQL per la sintassi corretta vicino a '' at line 3 – mahen3d
'delimitatore // CREA strip_tags function ($ str testo) Restituisce testo BEGIN DECLARE $ start, $ fine INT dI DEFAULT 1; LOOP SET $ start = LOCALIZZARE ("<", $ str, $ start); IF (! $ Start) THEN RETURN $ str; FINISCI SE; SET $ end = LOCATE (">", $ str, $ start); IF (! $ End) THEN SET $ end = $ start; FINISCI SE; SET $ str = INSERT ($ str, $ start, $ end - $ start + 1, ""); END LOOP; END // delimitatore; ' – nzn
FUNZIONE GOCCIA SE ESISTE strip_tags; DELIMITER | CREATE FUNCTION strip_tags ($ str text) RETURNS testo BEGIN DECLARE $ start, $ end INT DEFAULT 1; LOOP SET $ start = LOCATE ("<", $ str, $ start); IF (! $ Start) THEN RETURN $ str; FINISCI SE; SET $ end = LOCATE (">", $ str, $ start); IF (! $ End) THEN SET $ end = $ start; FINISCI SE; SET $ str = INSERT ($ str, $ start, $ end - $ start + 1, ""); FINE LOOP; END; | DELIMITER; – IRvanFauziE
Sto passando questo codice, sembra molto simile a quanto sopra. Ha funzionato per me, spero che aiuti.
BEGIN
DECLARE iStart, iEnd, iLength INT;
WHILE locate('<', Dirty) > 0 AND locate('>', Dirty, locate('<', Dirty)) > 0
DO
BEGIN
SET iStart = locate('<', Dirty), iEnd = locate('>', Dirty, locate('<', Dirty));
SET iLength = (iEnd - iStart) + 1;
IF iLength > 0 THEN
BEGIN
SET Dirty = insert(Dirty, iStart, iLength, '');
END;
END IF;
END;
END WHILE;
RETURN Dirty;
END
Ho fatto un piccolo benchmark approssimativo su 5000 (~ 20mb) vari campioni di testo semplice/html (descrizioni dei lavori raschiati). L'output del tuo esempio è esattamente lo stesso di Boann, tuttavia il tuo codice impiega circa 32 anni per essere elaborato e i soli 7 di Boann fanno ** la soluzione di Boann 4.5 volte più veloce **. Sto solo mettendo questo qui per riferimento futuro se qualcuno affronterà lo stesso dilemma come ho fatto io. Grazie a tutti e due ragazzi. –
I lavori di Boann una volta ho aggiunto SET $str = COALESCE($str, '');
.
da questo post:
Inoltre da notare, si consiglia di mettere un SET $ str = COALESCE ($ str, ''); appena prima del ciclo, altrimenti i valori nulli possono causare un'interruzione/mai query finale. - Tom C 17 agosto a 9:51
sto usando la libreria lib_mysqludf_preg per questo e una regex come questo:
SELECT PREG_REPLACE('#<[^>]+>#',' ',cell) FROM table;
Inoltre lo ha fatto in questo modo per le righe che con entità HTML codificati:
Ci sono probabilmente casi in cui questi potrebbero fallire ma non ne ho incontrato nessuno e sono ragionevolmente veloci.
Ho appena esteso la risposta @boann per consentire la destinazione di qualsiasi tag specifico in modo che possiamo sostituire i tag uno per uno con ciascuna chiamata di funzione. Hai solo bisogno di passare il parametro tag, ad es. 'a'
per sostituire tutte le etichette di ancoraggio di apertura/chiusura. Questo risponde alla domanda posta da OP, a differenza della risposta accettata, che elimina TUTTI i tag.
# MySQL function to programmatically replace out specified html tags from text/html fields
# run this to drop/update the stored function
DROP FUNCTION IF EXISTS `strip_tags`;
DELIMITER |
# function to nuke all opening and closing tags of type specified in argument 2
CREATE FUNCTION `strip_tags`($str text, $tag text) RETURNS text
BEGIN
DECLARE $start, $end INT DEFAULT 1;
SET $str = COALESCE($str, '');
LOOP
SET $start = LOCATE(CONCAT('<', $tag), $str, $start);
IF (!$start) THEN RETURN $str; END IF;
SET $end = LOCATE('>', $str, $start);
IF (!$end) THEN SET $end = $start; END IF;
SET $str = INSERT($str, $start, $end - $start + 1, '');
SET $str = REPLACE($str, CONCAT('</', $tag, '>'), '');
END LOOP;
END;
| DELIMITER ;
# test select to nuke all opening <a> tags
SELECT
STRIP_TAGS(description, 'a') AS stripped
FROM
tmpcat;
# run update query to replace out all <a> tags
UPDATE tmpcat
SET
description = STRIP_TAGS(description, 'a');
sì, probabilmente hai ragione :( – faq