68

我正在研究一个比较字符串的例程,但为了提高效率,我需要删除所有不是字母或数字的字符。

我现在正在使用多个REPLACE功能,但也许有更快更好的解决方案?

4

18 回答 18

98

使用 MySQL 8.0 或更高版本

感谢 michal.jakubeczy 在下面的回答,MySQL 现在支持用 Regex 替换:

UPDATE {table} SET {column} = REGEXP_REPLACE({column}, '[^0-9a-zA-Z ]', '')

使用 MySQL 5.7 或更低版本

此处不支持正则表达式。我必须创建自己的名为 alphanum 的函数,它为我剥离了字符:

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);
  IF str IS NOT NULL THEN 
    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; 
  ELSE
    SET ret='';
  END IF;
  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)

欢呼!

于 2014-04-07T04:24:31.990 回答
22

从性能的角度来看,(并假设你读的比写的多)

我认为最好的方法是预先计算和存储列的剥离版本,这样可以减少转换。

然后,您可以在新列上放置索引并让数据库为您完成工作。

于 2011-08-04T14:39:09.230 回答
14
SELECT teststring REGEXP '[[:alnum:]]+';

SELECT * FROM testtable WHERE test REGEXP '[[:alnum:]]+'; 

请参阅:http :
//dev.mysql.com/doc/refman/5.1/en/regexp.html 向下滚动到显示以下内容的部分: [:character_class:]

如果要操作字符串,最快的方法是使用 str_udf,请参阅:
https ://github.com/hholzgra/mysql-udf-regexp

于 2011-08-04T14:23:26.670 回答
14

从 MySQL 8.0 开始,您可以使用正则表达式从字符串中删除非字母数字字符。有方法REGEXP_REPLACE

这是删除非字母数字字符的代码:

UPDATE {table} SET {column} = REGEXP_REPLACE({column}, '[^0-9a-zA-Z ]', '')
于 2019-10-08T07:27:03.323 回答
9

拉丁和西里尔字符的直接且久经考验的解决方案:

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-привет ""]')
于 2016-11-10T04:02:10.973 回答
6

我能够找到(和使用)的最快方法是使用convert()。

来自 Doc。CONVERT() with USING 用于在不同字符集之间转换数据。

例子:

convert(string USING ascii)

在您的情况下,正确的字符集将是自定义的

来自 Doc 的注释。的USING形式从4.1.0CONVERT()开始可用。

于 2014-03-19T15:45:03.107 回答
6

根据Ryan Shillington 的回答,修改为使用超过 255 个字符的字符串并保留原​​始字符串中的空格。

仅供参考lower(str),最后。

我用它来比较字符串:

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 ;
于 2016-05-30T11:33:01.197 回答
4

我写了这个UDF。但是,它只修剪字符串开头的特殊字符。它还将字符串转换为小写。如果需要,您可以更新此功能。

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');

此外,您可以使用正则表达式,但这需要安装 MySql 扩展。

于 2012-08-13T19:54:05.007 回答
4

注意,像 ' 或 » 这样的字符被 MySQL 视为 alpha。最好使用类似的东西:

如果 c 在 'a' 和 'z' 之间或 c 在 'A' 和 'Z' 之间或 c 在 '0' 和 '9' 之间或 c = '-' 那么

于 2013-12-11T14:29:34.553 回答
3

这可以通过我在另一个答案中发布的正则表达式替换函数来完成,并在此处发表了博文。它可能不是最有效的解决方案,并且对于手头的工作可能看起来有点矫枉过正——但就像瑞士军刀一样,它可能会因为其他原因而派上用场。

可以在此 Rextester 在线演示中看到删除所有非字母数字字符的实际操作。

SQL (为简洁起见,不包括函数代码)

SELECT txt,
       reg_replace(txt,
                   '[^a-zA-Z0-9]+',
                   '',
                   TRUE,
                   0,
                   0
                   ) AS `reg_replaced`
FROM test;
于 2016-08-05T11:55:37.040 回答
1

到目前为止,唯一比这里的其他答案更简单的替代方法是确定列的完整特殊字符集,即目前该列中正在使用的所有特殊字符,然后依次替换所有这些字符,例如

update pages set slug = lower(replace(replace(replace(replace(name, ' ', ''), '-', ''), '.', ''), '&', '')); # replacing just space, -, ., & only

.

在已知数据集上是可取的,否则一些特殊字符通过黑名单方法而不是白名单方法溜过去是微不足道的。

显然,由于缺乏强大的内置白名单(例如,通过正则表达式替换),最简单的方法是在 sql 之外预先验证数据。

于 2014-03-20T19:39:08.410 回答
1

我在尝试匹配数据库中略有不同的姓氏时遇到了类似的问题。例如,有时人们将同一个人的名字输入为“McDonald”,也输入为“Mc Donald”,或“St John”和“St. John”。

我没有尝试转换 Mysql 数据,而是通过创建一个函数(在 PHP 中)来解决这个问题,该函数将接受一个字符串并创建一个仅限 alpha 的正则表达式:

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]*$';
}

现在我可以使用这样的查询来搜索数据库:

$lastname_regex = alpha_only_regex($lastname);
$query = "SELECT * FROM my_table WHERE lastname REGEXP '$lastname_regex';
于 2016-04-15T20:46:51.250 回答
0

我只需要在过程中获取字符串的字母字符,然后:

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;
于 2015-03-31T13:49:44.960 回答
0

需要替换非字母数字字符而不是删除非字母数字字符,所以我根据 Ryan Shillington 的字母数字创建了这个。适用于长度不超过 255 个字符的字符串

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 ; 

例子:

select 'hello world!',alphanum('hello world!'),alphanumreplace('hello world!','-');
+--------------+--------------------------+-------------------------------------+
| hello world! | alphanum('hello world!') | alphanumreplace('hello world!','-') |
+--------------+--------------------------+-------------------------------------+
| hello world! | helloworld               | hello-world-                        |
+--------------+--------------------------+-------------------------------------+

如果需要,您需要单独添加 alphanum 函数,我只是在这里作为示例。

于 2018-04-03T23:45:19.723 回答
-1

我尝试了一些解决方案,但最后使用了replace. 我的数据集是零件编号,我很清楚会发生什么。但为了理智,我使用 PHP 来构建长查询:

$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,' ',''),'-',''),'.',''),',',''),':',''),'?',''),'/',''),'!',''),'&',''),'@','')
于 2016-02-25T14:57:00.163 回答
-1

如果您使用的是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>";
} 
于 2017-04-04T01:34:50.537 回答
-1

alphanum 函数(自我回答)有一个错误,但我不知道为什么。对于文本“cas synt ls 75W140 1L”返回“cassyntls75W1401”,末尾的“L”缺少一些方法。

现在我用

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
//

(在谷歌上找到)

于 2017-04-05T15:18:28.420 回答
-2

与其他人相比,这可能是一个愚蠢的建议:

if(!preg_match("/^[a-zA-Z0-9]$/",$string)){
    $sortedString=preg_replace("/^[a-zA-Z0-9]+$/","",$string);
}
于 2014-03-19T20:40:19.133 回答