我在MySQL和Oracle中执行了相同的语句,但它们返回了不同的结果。正则表达式 ”/?”意思是返回零个或多个“/”,但是为什么MySQL会返回一个“产品”,是MySQL实现错误吗?
SELECT
REGEXP_SUBSTR('http://www.example.com/products',
'http://([[:alnum:]]+\.?){3,4}/?') "REGEXP_SUBSTR"
FROM DUAL;
Oracle Output:
REGEXP_SUBSTR
http://www.example.com/
MySQL Output:
REGEXP_SUBSTR
http://www.example.com/products
我查询了Oracle和MySQL的文档,他们对“?”的定义感兴趣,是匹配零个或一个字符。MySQL说他们实现了ICU库的常规支持。但是ICU的输出是“http:// www.example.com/”。
int main(int argc, char *argv[]) {
uint32_t flags = 0;
flags |= UREGEX_UNIX_LINES;
flags |= UREGEX_CASE_INSENSITIVE;
const char *c_source_char = "http://www.example.com/products";
const char *c_pat_char = "http://([[:alnum:]]+\\.?){3}/?";;
UErrorCode status = U_ZERO_ERROR;
URegularExpression *regexp = uregex_openC(c_pat_char, 0, NULL, &status);
UChar ustr[100];
u_uastrcpy(ustr, c_source_char);
uregex_setText(regexp, ustr, -1, &status);
if (uregex_find(regexp, 0, &status)) {
int32_t start = uregex_start(regexp, 0, &status);
int32_t end = uregex_end(regexp, 0, &status);
if(end - start > 0) {
std::string res(c_source_char+start, c_source_char+end);
std::cout << res << std::endl;
}
printf("Found match at %d-%d\n", start, end);
}
uregex_close(regexp);
return 0;
}
问题不在于
/?
,而在于前面的\.?
。
在 MySQL 中,正则表达式语法文档指出:
要在正则表达式中使用特殊字符的文字实例,请在其前面添加两个反斜杠 (
) 字符。 MySQL 解析器解释其中一个反斜杠,正则表达式库解释另一个。例如,要匹配包含特殊字符“+”的字符串 1+2,只有以下正则表达式中的最后一个才是正确的:\
mysql> SELECT REGEXP_LIKE('1+2', '1+2'); -> 0 mysql> SELECT REGEXP_LIKE('1+2', '1\+2'); -> 0 mysql> SELECT REGEXP_LIKE('1+2', '1\\+2'); -> 1
所以:
SELECT REGEXP_SUBSTR(
'http://www.example.com/products',
'http://([[:alnum:]]+\.?){3,4}/?'
) AS single_slash,
REGEXP_SUBSTR(
'http://www.example.com/products',
'http://([[:alnum:]]+\\.?){3,4}/?'
) AS double_slash,
REGEXP_SUBSTR(
'http://www.example.com/products',
'http://([[:alnum:]]+[.]?){3,4}/?'
) AS character_class
FROM DUAL;
输出:
单斜杠 | 双斜杠 | 角色_类别 |
---|---|---|
http://www.example.com/products | http://www.example.com/ | http://www.example.com/ |
在第一个模式中,
\.
与.
相同,并且匹配任何字符,因此[[:alnum:]]+\.?
匹配www.
然后example.
然后com/
然后products
第四次出现。要仅匹配 .
字符,您需要 \\.
或 [.]
。