如何从string中删除所有非字母数字字符?
我正在比较string的例程,但为了更好的效率,我需要删除所有不是字母或数字的字符。
我现在使用多个REPLACE
函数,但也许有一个更快,更好的解决scheme?
这些答案都没有为我工作。 我必须创造我自己的称为alphanum的function,剥夺了我的字符:
DROP FUNCTION IF EXISTS alphanum; DELIMITER | CREATE FUNCTION alphanum( str CHAR(32) ) RETURNS CHAR(16) 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); END IF; SET i = i + 1; END; UNTIL i > len END REPEAT; RETURN ret; END | DELIMITER ;
现在我可以这样做:
select 'This works finally!', alphanum('This works finally!');
我得到:
+---------------------+---------------------------------+ | This works finally! | alphanum('This works finally!') | +---------------------+---------------------------------+ | This works finally! | Thisworksfinally | +---------------------+---------------------------------+ 1 row in set (0.00 sec)
欢呼!
从性能的angular度来看,(假设你读得比你写得多)
我认为最好的方法是预先计算并存储一个已删除的列的版本,这样你就可以减less变换。
然后,您可以在新列上放置索引,并让数据库为您完成工作。
SELECT teststring REGEXP '[[:alnum:]]+'; SELECT * FROM testtable WHERE test REGEXP '[[:alnum:]]+';
请参阅: http : //dev.mysql.com/doc/refman/5.1/en/regexp.html
向下滚动到以下部分: [:character_class:]
如果你想操纵string,最快的方法是使用str_udf,参见:
https://github.com/hholzgra/mysql-udf-regexp
我写了这个UDF,但是我刚刚开始修改特殊字符,并转换为较低的值。 但是你可以更新这个function
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');
你也可以使用正则expression式,但是需要安装MySql扩展
我能够find(和使用)最快的方式是convert()。
从Doc。 CONVERT()与USING用于在不同字符集之间转换数据。
例:
convert(string USING ascii)
在你的情况下,正确的字符集将是自定义的
来自Doc。 CONVERT()
的USINGforms从4.1.0开始提供 。
请注意,像“或”这样的字符被MySQL视为alpha。 最好使用像这样的东西:
如果在“a”和“z”之间或c在“a”和“z”之间或c在“0”和“9”之间或c =“ – ”则
根据Ryan Shillington的回答 ,修改后可处理超过255个字符的string,并保留原始string的空格。
仅供参考,最终还是会lower(str)
。
我用这个来比较string:
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 ;
拉丁文和西里尔文字符的直接和战斗解决scheme:
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 ;
用法:
-- outputs "hello12356" SELECT remove_non_numeric_and_letters('hello - 12356-привет ""]')
我有一个类似的问题,试图匹配我们的数据库中的姓氏略有不同。 例如,有时人们input“麦当劳”,“麦当劳”,“圣约翰”和“圣约翰”的同名人名。
我没有试图转换Mysql数据,而是通过创build一个函数(在PHP中)来解决这个问题,该函数需要一个string并创build一个只有alpha的正则expression式:
function alpha_only_regex($str) { $alpha_only = str_split(preg_replace('/[^AZ]/i', '', $str)); return '^[^a-zA-Z]*'.implode('[^a-zA-Z]*', $alpha_only).'[^a-zA-Z]*$'; }
现在我可以用这样的查询来search数据库:
$lastname_regex = alpha_only_regex($lastname); $query = "SELECT * FROM my_table WHERE lastname REGEXP '$lastname_regex';
到目前为止,唯一可以比其他答案简单的方法是确定列的全部特殊字符,即当前正在使用的所有特殊字符,然后按顺序replace所有这些字符,例如
update pages set slug = lower(replace(replace(replace(replace(name, ' ', ''), '-', ''), '.', ''), '&', '')); # replacing just space, -, ., & only
。
这只对一组已知的数据是可取的,否则对于某些特殊字符而言,使用黑名单方法而不是白名单方法是微不足道的。
显然,最简单的方法是由于缺乏强大的内置白名单(例如,通过正则expression式replace)来预先validationsql以外的数据。
可能是一个愚蠢的build议与其他人相比:
if(!preg_match("/^[a-zA-Z0-9]$/",$string)){ $sortedString=preg_replace("/^[a-zA-Z0-9]+$/","",$string); }
我只需要在一个过程中只获得一个string的字母字符,并且做到了:
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;
我尝试了一些解决scheme,但在最后使用replace
。 我的数据集是零件号码,我相当清楚会发生什么。 但为了理智,我使用PHP来构build长查询:
$dirty = array(' ', '-', '.', ',', ':', '?', '/', '!', '&', '@'); $query = 'part_no'; foreach ($dirty as $dirt) { $query = "replace($query,'$dirt','')"; } echo $query;
这输出了我曾经头疼的东西:
replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(part_no,' ',''),'-',''),'.',''),',',''),':',''),'?',''),'/',''),'!',''),'&',''),'@','')
这可以通过在另一个答案中发布的正则expression式replace函数来完成。 (这可能不是最有效的解决办法,而且可能看起来有点矫枉过正,但被certificate是一种“瑞士军刀”,可能因其他原因而有用)。
在动作中可以看到删除所有非字母数字字符: SQL Fiddle演示 。
SQL (为简洁起见,不包括函数代码) :
SELECT txt, reg_replace(txt, '[^a-zA-Z0-9]+', '', TRUE, 0, 0 ) AS `reg_replaced` FROM test;
如果你使用的PHP然后….
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>"; }
alphanum函数(自我回答)有一个bug,但我不知道为什么。 对于文本“CAS合成器75W140 1L”返回“cassyntls75W1401”,从最后“L”是缺less一些如何。
现在我用
delimiter // DROP FUNCTION IF EXISTS alphanum // CREATE FUNCTION alphanum(prm_strInput varchar(255)) RETURNS VARCHAR(255) DETERMINISTIC BEGIN DECLARE i INT DEFAULT 1; DECLARE v_char VARCHAR(1); DECLARE v_parseStr VARCHAR(255) DEFAULT ' '; WHILE (i <= LENGTH(prm_strInput) ) DO SET v_char = SUBSTR(prm_strInput,i,1); IF v_char REGEXP '^[A-Za-z0-9]+$' THEN SET v_parseStr = CONCAT(v_parseStr,v_char); END IF; SET i = i + 1; END WHILE; RETURN trim(v_parseStr); END //
(在谷歌find)