2011-03-19 69 views
27

我有一個MySQL數據庫和我有一個查詢爲:MySQL的 - 返回匹配模式的REGEXP查詢

SELECT `id`, `originaltext` FROM `source` WHERE `originaltext` regexp '[0-9][0-9]' 

這個探測與在它2個位數編號的所有originaltexts。

我需要mysql返回這些數字作爲字段,所以我可以進一步操縱它們。理想情況下,如果我可以添加額外的標準應該是> 20會很好,但我也可以單獨做到這一點。

回答

12

如果您想在數據庫中使用更多正則表達式,可以考慮使用LIB_MYSQLUDF_PREG。這是一個導入PCRE庫的MySQL用戶函數的開源庫。 LIB_MYSQLUDF_PREG僅以源代碼形式提供。要使用它,你需要能夠編譯它並將其安裝到MySQL服務器中。安裝這個庫不會以任何方式改變MySQL的內置正則表達式支持。它僅提供以下附加功能:

PREG_CAPTURE從字符串中提取正則表達式匹配。 PREG_POSITION返回正則表達式與字符串匹配的位置。 PREG_REPLACE對字符串執行搜索和替換。 PREG_RLIKE測試一個正則表達式是否匹配一個字符串。

所有這些函數都將正則表達式作爲它們的第一個參數。這個正則表達式必須像Perl正則表達式運算符那樣格式化。例如。要測試正則表達式是否與主題不區分大小寫匹配,可以使用MySQL代碼PREG_RLIKE('/ regex/i',subject)。這與PHP的preg函數類似,這些函數還需要PHP字符串內正則表達式的額外//分隔符。

如果你想要更簡單的東西,你可以改變這個功能,以更好地滿足你的需求。

CREATE FUNCTION REGEXP_EXTRACT(string TEXT, exp TEXT) 
-- Extract the first longest string that matches the regular expression 
-- If the string is 'ABCD', check all strings and see what matches: 'ABCD', 'ABC', 'AB', 'A', 'BCD', 'BC', 'B', 'CD', 'C', 'D' 
-- It's not smart enough to handle things like (A)|(BCD) correctly in that it will return the whole string, not just the matching token. 

RETURNS TEXT 
DETERMINISTIC 
BEGIN 
    DECLARE s INT DEFAULT 1; 
    DECLARE e INT; 
    DECLARE adjustStart TINYINT DEFAULT 1; 
    DECLARE adjustEnd TINYINT DEFAULT 1; 

    -- Because REGEXP matches anywhere in the string, and we only want the part that matches, adjust the expression to add '^' and '$' 
    -- Of course, if those are already there, don't add them, but change the method of extraction accordingly. 

    IF LEFT(exp, 1) = '^' THEN 
    SET adjustStart = 0; 
    ELSE 
    SET exp = CONCAT('^', exp); 
    END IF; 

    IF RIGHT(exp, 1) = '$' THEN 
    SET adjustEnd = 0; 
    ELSE 
    SET exp = CONCAT(exp, '$'); 
    END IF; 

    -- Loop through the string, moving the end pointer back towards the start pointer, then advance the start pointer and repeat 
    -- Bail out of the loops early if the original expression started with '^' or ended with '$', since that means the pointers can't move 
    WHILE (s <= LENGTH(string)) DO 
    SET e = LENGTH(string); 
    WHILE (e >= s) DO 
     IF SUBSTRING(string, s, e) REGEXP exp THEN 
     RETURN SUBSTRING(string, s, e); 
     END IF; 
     IF adjustEnd THEN 
     SET e = e - 1; 
     ELSE 
     SET e = s - 1; -- ugh, such a hack to end it early 
     END IF; 
    END WHILE; 
    IF adjustStart THEN 
     SET s = s + 1; 
    ELSE 
     SET s = LENGTH(string) + 1; -- ugh, such a hack to end it early 
    END IF; 
    END WHILE; 

    RETURN NULL; 

END 
+0

嗯 - 我不認爲這是明顯的在我原來的職位,但原文已經得到了大量的文字「絨毛」的周圍數...我需要「解壓」的個數出來的。並且可能有一個原始文本中有多個數字... – Steve 2011-03-19 10:24:21

+0

我已更新答案。 – Pentium10 2011-03-19 10:36:32

8

MySQL中沒有任何使用正則表達式提取文本的語法。您可以使用REGEXP來標識包含兩個連續數字的行,但要解壓縮它們,您必須使用在這種情況下非常困難的普通字符串操作函數。

替代方案:

  • 從數據庫中選擇整個值,則使用客戶端上的正則表達式。
  • 使用更好的支持SQL標準的不同數據庫(可能不是我所知的選項)。那麼你可以使用這個:SUBSTRING(originaltext from '%#[0-9]{2}#%' for '#')
+0

我同意。我的直覺是從數據庫中獲取整個字段,然後使用腳本將其與正則表達式進行比較並提取匹配。 – dgmdan 2012-02-01 15:55:42

2

我有同樣的問題,這是我找到的解決方法(但它不會在所有情況下工作):

  • 使用LOCATE()找到開頭和結尾部分字符串你wan't匹配
  • 使用MID()提取子之間...
  • 守正則表達式匹配只有你一定能找到一個匹配,其中行。
+7

這裏的一個例子可能會有所幫助 – Geoff 2015-03-03 18:34:57

2

我用我的代碼作爲存儲過程(函數),應該工作以提取任何數字在一個塊中建立的數字。這是我更廣泛的圖書館的一部分。

DELIMITER $$ 

-- 2013.04 [email protected] 
-- FindNumberInText("ab 234 95 cd", TRUE) => 234 
-- FindNumberInText("ab 234 95 cd", FALSE) => 95 

DROP FUNCTION IF EXISTS FindNumberInText$$ 
CREATE FUNCTION FindNumberInText(_input VARCHAR(64), _fromLeft BOOLEAN) RETURNS VARCHAR(32) 
BEGIN 
    DECLARE _r    VARCHAR(32) DEFAULT ''; 
    DECLARE _i    INTEGER DEFAULT 1; 
    DECLARE _start   INTEGER DEFAULT 0; 
    DECLARE _IsCharNumeric BOOLEAN; 

    IF NOT _fromLeft THEN SET _input = REVERSE(_input); END IF; 
    _loop: REPEAT 
    SET _IsCharNumeric = LOCATE(MID(_input, _i, 1), "") > 0; 
    IF _IsCharNumeric THEN 
     IF _start = 0 THEN SET _start = _i; END IF; 
    ELSE 
     IF _start > 0 THEN LEAVE _loop;  END IF; 
    END IF; 
    SET _i = _i + 1; 
    UNTIL _i > length(_input) END REPEAT; 

    IF _start > 0 THEN 
    SET _r = MID(_input, _start, _i - _start); 
    IF NOT _fromLeft THEN SET _r = REVERSE(_r); END IF; 
    END IF; 
    RETURN _r; 
END$$ 
0

如果你想返回一個字符串的一部分:

SELECT id , substring(columnName,(locate('partOfString',columnName)),10) from tableName; 

Locate()將返回匹配字符串的開頭現在的位置成爲首發的Function Substring()

0

位置我知道這是相當一段時間以來,這個問題被問到,但遇到它,並認爲這將是我的自定義正則表達式替代品一個很好的挑戰 - 見this blog post

...好消息是它可以,但它需要被稱爲不少次。請參閱this online rextester demo,其中顯示了下面SQL的工作方式。

SELECT reg_replace(
     reg_replace(
      reg_replace(
      reg_replace(
       reg_replace(
       reg_replace(
        reg_replace(txt, 
           '[^0-9]+', 
           ',', 
           TRUE, 
           1, -- Min match length 
           0 -- No max match length 
           ), 
          '([0-9]{3,}|,[0-9],)', 
          '', 
          TRUE, 
          1, -- Min match length 
          0 -- No max match length 
          ), 
          '^[0-9],', 
          '', 
          TRUE, 
          1, -- Min match length 
          0 -- No max match length 
          ), 
         ',[0-9]$', 
         '', 
         TRUE, 
         1, -- Min match length 
         0 -- No max match length 
         ), 
         ',{2,}', 
         ',', 
         TRUE, 
         1, -- Min match length 
         0 -- No max match length 
         ), 
        '^,', 
        '', 
        TRUE, 
        1, -- Min match length 
        0 -- No max match length 
        ), 
        ',$', 
        '', 
        TRUE, 
        1, -- Min match length 
        0 -- No max match length 
        ) AS `csv` 
FROM tbl;