文字列を比較するルーチンに取り組んでいますが、効率を高めるために、文字または数字以外のすべての文字を削除する必要があります。
現在、複数のREPLACE
機能を使用していますが、より高速で優れたソリューションがあるのではないでしょうか?
文字列を比較するルーチンに取り組んでいますが、効率を高めるために、文字または数字以外のすべての文字を削除する必要があります。
現在、複数のREPLACE
機能を使用していますが、より高速で優れたソリューションがあるのではないでしょうか?
以下の michal.jakubeczy の回答のおかげで、正規表現による置き換えが MySQL でサポートされるようになりました。
UPDATE {table} SET {column} = REGEXP_REPLACE({column}, '[^0-9a-zA-Z ]', '')
ここでは正規表現はサポートされていません。文字を削除する 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)
万歳!
パフォーマンスの観点から (書くよりも読む方が多いという前提で)
最善の方法は、列の削除されたバージョンを事前に計算して保存することだと思います。このようにして、変換を少なくします。
次に、新しい列にインデックスを配置し、データベースに作業を任せることができます。
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 を参照してください。
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 ;
この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 拡張機能をインストールする必要があります。
データベース内のわずかに異なる姓を一致させようとすると、同様の問題が発生しました。たとえば、「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';
おそらく他の人に比べてばかげた提案です:
if(!preg_match("/^[a-zA-Z0-9]$/",$string)){
$sortedString=preg_replace("/^[a-zA-Z0-9]+$/","",$string);
}