68

文字列を比較するルーチンに取り組んでいますが、効率を高めるために、文字または数字以外のすべての文字を削除する必要があります。

現在、複数のREPLACE機能を使用していますが、より高速で優れたソリューションがあるのではないでしょうか?

4

18 に答える 18

98

MySQL 8.0 以降を使用する

以下の michal.jakubeczy の回答のおかげで、正規表現による置き換えが MySQL でサポートされるようになりました。

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 に答える
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 に答える
1

データベース内のわずかに異なる姓を一致させようとすると、同様の問題が発生しました。たとえば、「McDonald」と「Mc Donald」、または「St John」と「St. John」と同じ人の名前を入力することがありました。

Mysql データを変換しようとする代わりに、文字列を受け取ってアルファのみの正規表現を作成する関数を (PHP で) 作成することで問題を解決しました。

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 に答える
-2

おそらく他の人に比べてばかげた提案です:

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