Je travaille sur une routine qui compare les chaînes, mais pour une meilleure efficacité, je dois supprimer tous les caractères qui ne sont ni des lettres ni des chiffres.
J'utilise plusieurs fonctions REPLACE
maintenant, mais peut-être y a-t-il une solution plus rapide et plus agréable?
Aucune de ces réponses n'a fonctionné pour moi. Je devais créer ma propre fonction appelée alphanum qui supprimait les caractères pour moi:
DROP FUNCTION IF EXISTS alphanum;
DELIMITER |
CREATE FUNCTION alphanum( str CHAR(255) ) RETURNS CHAR(255) DETERMINISTIC
BEGIN
DECLARE i, len SMALLINT DEFAULT 1;
DECLARE ret CHAR(255) DEFAULT '';
DECLARE c CHAR(1);
SET len = CHAR_LENGTH( str );
REPEAT
BEGIN
SET c = MID( str, i, 1 );
IF c REGEXP '[[:alnum:]]' THEN
SET ret=CONCAT(ret,c);
END IF;
SET i = i + 1;
END;
UNTIL i > len END REPEAT;
RETURN ret;
END |
DELIMITER ;
Maintenant je peux faire:
select 'This works finally!', alphanum('This works finally!');
et je reçois:
+---------------------+---------------------------------+
| This works finally! | alphanum('This works finally!') |
+---------------------+---------------------------------+
| This works finally! | Thisworksfinally |
+---------------------+---------------------------------+
1 row in set (0.00 sec)
Hourra!
Du point de vue de la performance, (Et en supposant que vous lisiez plus que vous n’écrivez)
Je pense que le meilleur moyen serait de pré-calculer et de stocker une version épurée de la colonne, Ainsi, vous transformerez moins.
Vous pouvez ensuite mettre un index sur la nouvelle colonne et demander à la base de données de faire le travail à votre place.
SELECT teststring REGEXP '[[:alnum:]]+';
SELECT * FROM testtable WHERE test REGEXP '[[:alnum:]]+';
Voir: http://dev.mysql.com/doc/refman/5.1/en/regexp.html
Faites défiler jusqu'à la section qui dit:[:character_class:]
Si vous voulez manipuler des chaînes, le moyen le plus rapide consiste à utiliser un str_udf, voir:
https://github.com/hholzgra/mysql-udf-regexp
Basé sur la réponse de Ryan Shillington , modifiée pour fonctionner avec des chaînes de plus de 255 caractères et en préservant les espaces de la chaîne d'origine.
Pour info il y a lower(str)
à la fin.
Je l'ai utilisé pour comparer des chaînes:
DROP FUNCTION IF EXISTS spacealphanum;
DELIMITER $$
CREATE FUNCTION `spacealphanum`( str TEXT ) RETURNS TEXT CHARSET utf8
BEGIN
DECLARE i, len SMALLINT DEFAULT 1;
DECLARE ret TEXT DEFAULT '';
DECLARE c CHAR(1);
SET len = CHAR_LENGTH( str );
REPEAT
BEGIN
SET c = MID( str, i, 1 );
IF c REGEXP '[[:alnum:]]' THEN
SET ret=CONCAT(ret,c);
ELSEIF c = ' ' THEN
SET ret=CONCAT(ret," ");
END IF;
SET i = i + 1;
END;
UNTIL i > len END REPEAT;
SET ret = lower(ret);
RETURN ret;
END $$
DELIMITER ;
Le moyen le plus rapide que j'ai pu trouver (et utiliser) est avec convert ().
de Doc. CONVERT () avec USING est utilisé pour convertir les données entre différents jeux de caractères.
Exemple:
convert(string USING ascii)
Dans votre cas, le jeu de caractères droit sera défini par vous-même
NOTE de Doc. Le formulaire UTILISANT de CONVERT()
est disponible à partir de 4.1.0 .
Attention, les caractères tels que ’ou 'sont considérés comme alpha par MySQL . Il vaut mieux utiliser quelque chose comme:
SI c ENTRE 'a' ET 'z' OR c ENTRE 'A' ET 'Z' OR c ENTRE '0' ET '9' OR c = '-' ALORS
J'ai écrit cette UDF. Cependant, seuls les caractères spéciaux au début de la chaîne sont supprimés. Il convertit également la chaîne en minuscule. Vous pouvez mettre à jour cette fonction si vous le souhaitez.
DELIMITER //
DROP FUNCTION IF EXISTS DELETE_DOUBLE_SPACES//
CREATE FUNCTION DELETE_DOUBLE_SPACES ( title VARCHAR(250) )
RETURNS VARCHAR(250) DETERMINISTIC
BEGIN
DECLARE result VARCHAR(250);
SET result = REPLACE( title, ' ', ' ' );
WHILE (result <> title) DO
SET title = result;
SET result = REPLACE( title, ' ', ' ' );
END WHILE;
RETURN result;
END//
DROP FUNCTION IF EXISTS LFILTER//
CREATE FUNCTION LFILTER ( title VARCHAR(250) )
RETURNS VARCHAR(250) DETERMINISTIC
BEGIN
WHILE (1=1) DO
IF( ASCII(title) BETWEEN ASCII('a') AND ASCII('z')
OR ASCII(title) BETWEEN ASCII('A') AND ASCII('Z')
OR ASCII(title) BETWEEN ASCII('0') AND ASCII('9')
) THEN
SET title = LOWER( title );
SET title = REPLACE(
REPLACE(
REPLACE(
title,
CHAR(10), ' '
),
CHAR(13), ' '
) ,
CHAR(9), ' '
);
SET title = DELETE_DOUBLE_SPACES( title );
RETURN title;
ELSE
SET title = SUBSTRING( title, 2 );
END IF;
END WHILE;
END//
DELIMITER ;
SELECT LFILTER(' !@#$%^&*()_+1a b');
Vous pouvez également utiliser des expressions régulières, mais cela nécessite l'installation d'une extension MySql.
Solution simple et directe pour les caractères latins et cyrilliques:
DELIMITER //
CREATE FUNCTION `remove_non_numeric_and_letters`(input TEXT)
RETURNS TEXT
BEGIN
DECLARE output TEXT DEFAULT '';
DECLARE iterator INT DEFAULT 1;
WHILE iterator < (LENGTH(input) + 1) DO
IF SUBSTRING(input, iterator, 1) IN
('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я', 'а', 'б', 'в', 'г', 'д', 'е', 'ж', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', 'п', 'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ч', 'ш', 'щ', 'ъ', 'ы', 'ь', 'э', 'ю', 'я')
THEN
SET output = CONCAT(output, SUBSTRING(input, iterator, 1));
END IF;
SET iterator = iterator + 1;
END WHILE;
RETURN output;
END //
DELIMITER ;
Usage:
-- outputs "hello12356"
SELECT remove_non_numeric_and_letters('hello - 12356-привет ""]')
Cela peut être fait avec une fonction de remplacement d'expression régulière que j'ai postée dans une autre réponse et que j'ai blogué à propos de ici . Ce n'est peut-être pas la solution la plus efficace possible et peut paraître exagéré pour le travail à accomplir - mais, à l'instar d'un couteau suisse, il peut s'avérer utile pour d'autres raisons.
Vous pouvez le voir en action supprimer tous les caractères non alphanumériques dans cette démonstration en ligne de Rextester .
SQL (à l'exception du code de fonction pour plus de concision)}:
SELECT txt,
reg_replace(txt,
'[^a-zA-Z0-9]+',
'',
TRUE,
0,
0
) AS `reg_replaced`
FROM test;
Jusqu'ici, la seule approche alternative moins compliquée que les autres réponses ici est de déterminer l'ensemble des caractères spéciaux de la colonne, c'est-à-dire tous les caractères spéciaux utilisés dans cette colonne pour le moment, puis d'effectuer un remplacement séquentiel de tous ces personnages, par exemple.
update pages set slug = lower(replace(replace(replace(replace(name, ' ', ''), '-', ''), '.', ''), '&', '')); # replacing just space, -, ., & only
.
Ceci est seulement recommandé sur un ensemble de données connu, sinon c'est trivial pour certains personnages spéciaux de glisser avec un approche liste noire au lieu d'une approche liste blanche.
De toute évidence, le moyen le plus simple est de valider à l'avance les données en dehors de SQL en raison de l'absence de liste blanche intégrée robuste (par exemple, via un remplacement de regex).
J'ai eu un problème similaire en essayant de faire correspondre des noms de famille légèrement différents dans notre base de données. Par exemple, il arrive que des personnes inscrivent le même nom de personne sous les noms "McDonald", ainsi que "Mc Donald" ou "St John" et "St. John".
Au lieu d'essayer de convertir les données Mysql, j'ai résolu le problème en créant une fonction (en PHP) qui prendrait une chaîne et créerait une expression régulière alpha uniquement:
function alpha_only_regex($str) {
$alpha_only = str_split(preg_replace('/[^A-Z]/i', '', $str));
return '^[^a-zA-Z]*'.implode('[^a-zA-Z]*', $alpha_only).'[^a-zA-Z]*$';
}
Maintenant, je peux chercher dans la base de données avec une requête comme celle-ci:
$lastname_regex = alpha_only_regex($lastname);
$query = "SELECT * FROM my_table WHERE lastname REGEXP '$lastname_regex';
Je devais obtenir uniquement les caractères alphabétiques d'une chaîne dans une procédure et j'ai:
SET @source = "whatever you want";
SET @target = '';
SET @i = 1;
SET @len = LENGTH(@source);
WHILE @i <= @len DO
SET @char = SUBSTRING(@source, @i, 1);
IF ((ORD(@char) >= 65 && ORD(@char) <= 90) || (ORD(@char) >= 97 && ORD(@char) <= 122)) THEN
SET @target = CONCAT(@target, @char);
END IF;
SET @i = @i + 1;
END WHILE;
Nécessaire pour remplacer les caractères non alphanumériques plutôt que de supprimer les caractères non alphanumériques, j'ai donc créé ce modèle à partir de l'alphanum de Ryan Shillington. Fonctionne pour les chaînes d'une longueur maximale de 255 caractères
DROP FUNCTION IF EXISTS alphanumreplace;
DELIMITER |
CREATE FUNCTION alphanumreplace( str CHAR(255), d CHAR(32) ) RETURNS CHAR(255)
BEGIN
DECLARE i, len SMALLINT DEFAULT 1;
DECLARE ret CHAR(32) DEFAULT '';
DECLARE c CHAR(1);
SET len = CHAR_LENGTH( str );
REPEAT
BEGIN
SET c = MID( str, i, 1 );
IF c REGEXP '[[:alnum:]]' THEN SET ret=CONCAT(ret,c);
ELSE SET ret=CONCAT(ret,d);
END IF;
SET i = i + 1;
END;
UNTIL i > len END REPEAT;
RETURN ret;
END |
DELIMITER ;
Exemple:
select 'hello world!',alphanum('hello world!'),alphanumreplace('hello world!','-');
+--------------+--------------------------+-------------------------------------+
| hello world! | alphanum('hello world!') | alphanumreplace('hello world!','-') |
+--------------+--------------------------+-------------------------------------+
| hello world! | helloworld | hello-world- |
+--------------+--------------------------+-------------------------------------+
Vous aurez besoin d'ajouter la fonction alphanum séparément si vous le souhaitez, je l'ai juste ici pour l'exemple.
J'ai essayé quelques solutions, mais à la fin j'ai utilisé replace
. Mon ensemble de données est composé de références et je sais à quoi m'attendre. Mais pour des raisons de santé mentale, j’ai utilisé PHP pour construire la requête longue:
$dirty = array(' ', '-', '.', ',', ':', '?', '/', '!', '&', '@');
$query = 'part_no';
foreach ($dirty as $dirt) {
$query = "replace($query,'$dirt','')";
}
echo $query;
Cela génère quelque chose qui me donnait mal à la tête:
replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(part_no,' ',''),'-',''),'.',''),',',''),':',''),'?',''),'/',''),'!',''),'&',''),'@','')
si vous utilisez php alors ....
try{
$con = new PDO ("mysql:Host=localhost;dbname=dbasename","root","");
}
catch(PDOException $e){
echo "error".$e-getMessage();
}
$select = $con->prepare("SELECT * FROM table");
$select->setFetchMode(PDO::FETCH_ASSOC);
$select->execute();
while($data=$select->fetch()){
$id = $data['id'];
$column = $data['column'];
$column = preg_replace("/[^a-zA-Z0-9]+/", " ", $column); //remove all special characters
$update = $con->prepare("UPDATE table SET column=:column WHERE id='$id'");
$update->bindParam(':column', $column );
$update->execute();
// echo $column."<br>";
}