programing

MySQL에서 대소문자를 구분하지 않는 REPLACE?

goodsources 2023. 8. 29. 20:31
반응형

MySQL에서 대소문자를 구분하지 않는 REPLACE?

MySQL은 기본 정렬에서 거의 모든 문자열 비교를 실행합니다...을 제외하고REPLACE지휘권대/소문자를 구분하지 않는 데이터 정렬이 있으므로 대/소문자를 구분하지 않고REPLACE강제로 할 수 있는 방법이 있습니까?REPLACE항상 대/소문자를 구분하는 비교를 수행하는 것이 아니라 현재의 대조를 사용하는 것입니까?MySQL(현재 5.1 실행 중)을 업그레이드하여 추가 기능을 사용할 수 있습니다...

mysql> charset utf8 collation utf8_unicode_ci;
Charset changed

mysql> select 'abc' like '%B%';
+------------------+
| 'abc' like '%B%' |
+------------------+
|                1 |
+------------------+

mysql> select replace('aAbBcC', 'a', 'f');
+-----------------------------+
| replace('aAbBcC', 'a', 'f') |
+-----------------------------+
| fAbBcC                      |   <--- *NOT* 'ffbBcC'
+-----------------------------+

한다면replace(lower())작동하지 않습니다. 다른 기능을 만들어야 합니다.

내 2센트.

많은 사람들이 MySQL에서 MariaDB로 이주했기 때문에, 그 사람들은 다음과 같은 새로운 기능을 사용할 수 있을 것입니다.REGEXP_REPLACE일반적으로 대체하는 것처럼 사용하지만 패턴은 정규식입니다.

다음은 작동 예입니다.

UPDATE `myTable`
SET `myField` = REGEXP_REPLACE(`myField`, '(?i)my insensitive string', 'new string') 
WHERE `myField` REGEXP '(?i)my insensitive string'

옵션(?i)이후의 모든 일치 항목은 대소문자를 구분하지 않습니다(나처럼 패턴의 시작 부분에 놓이면 모든 일치 항목이 구분하지 않습니다).

자세한 내용은 여기를 참조하십시오. https://mariadb.com/kb/en/mariadb/pcre/

편집: MySQL 8.0부터 이제 사용할 수 있습니다.regexp_replace기능도 마찬가지입니다. 설명서 참조: https://dev.mysql.com/doc/refman/8.0/en/regexp.html

fvox에서 말하는 것에 대한 대체 기능.

DELIMITER |
CREATE FUNCTION case_insensitive_replace ( REPLACE_WHERE text, REPLACE_THIS text, REPLACE_WITH text )
RETURNS text
DETERMINISTIC 
BEGIN
    DECLARE last_occurency int DEFAULT '1';

    IF LCASE(REPLACE_THIS) = LCASE(REPLACE_WITH) OR LENGTH(REPLACE_THIS) < 1 THEN
         RETURN REPLACE_WHERE;
    END IF;

    WHILE Locate( LCASE(REPLACE_THIS), LCASE(REPLACE_WHERE), last_occurency ) > 0  DO
      BEGIN
        SET last_occurency = Locate(LCASE(REPLACE_THIS), LCASE(REPLACE_WHERE));
         SET REPLACE_WHERE = Insert( REPLACE_WHERE, last_occurency, LENGTH(REPLACE_THIS), REPLACE_WITH);
         SET last_occurency = last_occurency + LENGTH(REPLACE_WITH);
      END;
    END WHILE;
    RETURN REPLACE_WHERE;
END;
|
DELIMITER ;

소규모 테스트:

SET @str = BINARY 'New York';
SELECT case_insensitive_replace(@str, 'y', 'K');

답변:New Kork

Luist의 답변을 수정하면 바늘을 케이스가 다른 버전의 바늘로 교체할 수 있습니다(두 줄이 변경됨).

DELIMITER |
CREATE FUNCTION case_insensitive_replace ( REPLACE_WHERE text, REPLACE_THIS text, REPLACE_WITH text )
RETURNS text
DETERMINISTIC 
BEGIN
  DECLARE last_occurency int DEFAULT '1';

  IF LENGTH(REPLACE_THIS) < 1 THEN
    RETURN REPLACE_WHERE;
  END IF;

  WHILE Locate( LCASE(REPLACE_THIS), LCASE(REPLACE_WHERE), last_occurency ) > 0  DO
    BEGIN
      SET last_occurency = Locate(LCASE(REPLACE_THIS), LCASE(REPLACE_WHERE), last_occurency);
      SET REPLACE_WHERE = Insert( REPLACE_WHERE, last_occurency, LENGTH(REPLACE_THIS), REPLACE_WITH);
       SET last_occurency = last_occurency + LENGTH(REPLACE_WITH);
    END;
  END WHILE;
  RETURN REPLACE_WHERE;
END;
|
DELIMITER ;

저는 대/소문자 구분 대체를 통해 대/소문자 구분 없이 검색을 수행하는 http://pento.net/2009/02/15/case-insensitive-replace-for-mysql/ (infvox's answer)과 함께 갔습니다. 검색 문자열의 다른 곳에서 영향을 받지 않는 문자가 무엇인지에 대한 대/소문자를 변경하지 않습니다.

N.B. 같은 페이지에서 CHAR(255)를 VARCHAR(255)로 변경해야 한다는 의견을 추가로 제시했습니다. 이것은 저에게도 필요한 것으로 보입니다.

이전 답변 및 pento.net 링크에서 다음과 같은 주장을 펼칩니다.LOCATE()소문자입니다.

LOCATE는 기본적으로 대소문자를 구분하지 않으므로 리소스 낭비입니다.

mysql> select locate('el', 'HELLo');
+-----------------------+
| locate('el', 'HELLo') |
+-----------------------+
|                     2 |
+-----------------------+

대체할 수 있습니다.

WHILE Locate( LCASE(REPLACE_THIS), LCASE(REPLACE_WHERE), last_occurency ) > 0 DO

와 함께

WHILE Locate(REPLACE_THIS, REPLACE_WHERE, last_occurency ) > 0 DO

기타.

'특수' 문자의 경우 예상치 못한 동작이 발생합니다.

SELECT case_insensitive_replace('A', 'Ã', 'a')

기브즈

a

예상치 못한 일이...우리는 A가 아닌 ã만 교체하기를 원하기 때문에.

더 이상한 것은:

SELECT LOCATE('Ã', 'A');

기브즈

0

정확한 결과는...저장된 절차의 매개변수를 인코딩하는 것과 관련이 있는 것 같습니다

저는 원래의 검색 문자열이나 검색 문자열의 경우를 걱정하지 않고 교체해야 할 때 만든 검색 및 교체 기능을 사용하는 것을 좋아합니다.수신 문자열을 변경하지 않고 빈/null 검색 문자열이나 null 대체 문자열을 전달하면 이 루틴이 빠르게 실행됩니다.검색이 계속 반복될 경우를 대비해 안전 카운트 다운도 추가했습니다.이렇게 하면 우리는 영원히 고리에 갇히지 않습니다.너무 낮다고 생각되면 시작 번호를 변경합니다.

delimiter //

DROP FUNCTION IF EXISTS `replace_nocase`//

CREATE FUNCTION `replace_nocase`(raw text, find_str varchar(1000), replace_str varchar(1000)) RETURNS text
CHARACTER SET utf8
DETERMINISTIC
BEGIN
    declare ret text;
    declare len int;
    declare hit int;
    declare safe int;
    
    if find_str is null or find_str='' or replace_str is null then
        return raw;
    end if;

    set safe=10000;
    set ret=raw;
    set len=length(find_str);
    
    set hit=LOCATE(find_str,ret);
    while hit>0 and safe>0 do
        set ret=concat(substring(ret,1,hit-1),replace_str,substring(ret,hit+len));
        set hit=LOCATE(find_str,ret,hit+1);
        set safe=safe-1;
    end while;
    

    return ret;
END//

이 질문은 조금 오래된 것이지만 저는 같은 문제에 부딪혔고 주어진 답들은 제가 그것을 완전히 풀 수 있도록 허락하지 않았습니다.

저는 그 결과가 원래 문자열의 케이스를 유지하기를 원했습니다.

그래서 나는 약간의 수정을 했습니다.replace_ci에 의해제안된 :fvox는 다음과 .

DELIMITER $$

DROP FUNCTION IF EXISTS `replace_ci`$$

CREATE FUNCTION `replace_ci` (str TEXT, needle CHAR(255), str_rep CHAR(255))
RETURNS TEXT
DETERMINISTIC
BEGIN
DECLARE return_str TEXT DEFAULT '';
DECLARE lower_str TEXT;
DECLARE lower_needle TEXT;
DECLARE tmp_needle TEXT;
DECLARE str_origin_char CHAR(1);
DECLARE str_rep_char CHAR(1);
DECLARE final_str_rep TEXT DEFAULT '';
DECLARE pos INT DEFAULT 1;
DECLARE old_pos INT DEFAULT 1;
DECLARE needle_pos INT DEFAULT 1;

IF needle = '' THEN
    RETURN str;
END IF;

SELECT LOWER(str) INTO lower_str;
SELECT LOWER(needle) INTO lower_needle;
SELECT LOCATE(lower_needle, lower_str, pos) INTO pos;
WHILE pos > 0 DO
    SELECT substr(str, pos, char_length(needle)) INTO tmp_needle;
    SELECT '' INTO final_str_rep;
    SELECT 1 INTO needle_pos;
    WHILE needle_pos <= char_length(tmp_needle) DO
        SELECT substr(tmp_needle, needle_pos, 1) INTO str_origin_char;
        SELECT SUBSTR(str_rep, needle_pos, 1) INTO str_rep_char;
        SELECT CONCAT(final_str_rep, IF(BINARY str_origin_char = LOWER(str_origin_char), LOWER(str_rep_char), IF(BINARY str_origin_char = UPPER(str_origin_char), UPPER(str_rep_char), str_rep_char))) INTO final_str_rep;
        SELECT (needle_pos + 1) INTO needle_pos;
    END WHILE;
    SELECT CONCAT(return_str, SUBSTR(str, old_pos, pos - old_pos), final_str_rep) INTO return_str;
    SELECT pos + CHAR_LENGTH(needle) INTO pos;
    SELECT pos INTO old_pos;
    SELECT LOCATE(lower_needle, lower_str, pos) INTO pos;
END WHILE;
SELECT CONCAT(return_str, SUBSTR(str, old_pos, CHAR_LENGTH(str))) INTO return_str;
RETURN return_str;
END$$

DELIMITER ;

사용 예:

SELECT replace_ci( 'MySQL', 'm', 'e' ) as replaced;

반환 예정: | 대체됨 | | --- | EySQL |

언급URL : https://stackoverflow.com/questions/5656056/case-insensitive-replace-in-mysql

반응형