我有一个MySQL数据库,我有一个查询:
SELECT `id`, `originaltext` FROM `source` WHERE `originaltext` regexp '[0-9][0-9]'
这将检测所有包含2位数字的原始文本。
我需要MySQL将这些数字作为字段返回,因此我可以进一步操作它们。
理想情况下,如果我可以添加其他标准,那么应该是> 20会很棒,但我也可以分开做。
答案 0 :(得分: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
答案 1 :(得分:9)
MySQL中没有任何语法可以使用正则表达式提取文本。您可以使用REGEXP来标识包含两个连续数字的行,但要提取它们,您必须使用普通的字符串操作函数,在这种情况下非常困难。
备选方案:
SUBSTRING(originaltext from '%#[0-9]{2}#%' for '#')
。答案 2 :(得分:2)
我遇到了同样的问题,这是我找到的解决方案(但不会在所有情况下都有效):
LOCATE()
查找您不匹配的字符串的开头和结尾MID()
提取其间的子字符串...... 答案 3 :(得分:2)
我使用我的代码作为存储过程(函数),应该提取从单个块中的数字构建的任何数字。这是我更广泛的图书馆的一部分。
DELIMITER $$
-- 2013.04 michal@glebowski.pl
-- 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), "0123456789") > 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$$
答案 4 :(得分:0)
如果要返回字符串的一部分:
SELECT id , substring(columnName,(locate('partOfString',columnName)),10) from tableName;
Locate()
将返回匹配字符串的起始位置,该字符串将成为Function Substring()
的起始位置
答案 5 :(得分: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;
答案 6 :(得分:0)
我认为更干净的方法是使用REGEXP_SUBSTR()
:
这将精确提取两个数字:
SELECT REGEXP_SUBSTR(`originalText`,'[0-9]{2}') AS `twoDigits` FROM `source`;
这将精确地提取两位数,但从20-99(例如:1112
返回null; 1521
返回52
):
SELECT REGEXP_SUBSTR(`originalText`,'[2-9][0-9]') AS `twoDigits` FROM `source`;
我在v8.0中都进行了测试,并且它们都能正常工作。就是这样,祝你好运!