php多语言截取字符串函数

本文介绍了PHP中的自定义函数msubstr,用于根据指定长度截取字符串,支持中文和英文截取,并可以设置是否添加省略号。
<?php
header("Content-Type:text/html;charset=utf-8");
function msubstr($str, $start = 0, $length, $lenth2, $suffix = true){ 
//$length 中文截取长度,$lenth2英文截取长度 $suffix 是否省略号 
$charset = 'utf-8'; 
if (LANG_SET != 'zh'){ 
    $length = $lenth2; 
} 
$str = preg_replace("/(\<[^\<]*\>|\r|\n|\s|\[.+?\])/is", ' ', $str); 
if (function_exists("mb_substr")) 
    $slice = mb_substr($str, $start, $length, $charset); 
elseif (function_exists('iconv_substr')) { 
    $slice = iconv_substr($str, $start, $length, $charset); 
    if (false === $slice) { 
        $slice = ''; 
    } 
} else { 
    $re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/"; 
    $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/"; 
    $re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/"; 
    $re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/"; 
    preg_match_all($re[$charset], $str, $match); 
    $slice = join("", array_slice($match[0], $start, $length)); 
} 
$fix = ''; 
if (LANG_SET == 'zh') { 
    $slice = str_replace(' ', '', $slice); 
    if (strlen($slice) > $length) { 
        $fix = '...'; 
    } 
} else { 
    if (strlen($str) > $lenth2) { 
        $fix = '...'; 
    } 
} 
return $suffix ? $slice . $fix : $slice; 
}

$str = "dsd个法师dsad打发dd的撒ddsddsadsadsads的撒";

echo msubstr($str,1,2,20,true);

?>

 

<think>我们正在使用MySQL 5.7版本,该版本原生不支持正则表达式截取函数(如REGEXP_SUBSTR)。在MySQL 8.0之前,没有内置的正则表达式提取函数。但是,我们可以通过其他方式模拟实现类似功能。 根据引用[1]和[3]的提示,我们可以使用MySQL的字符串函数(如SUBSTRING_INDEX, LOCATE等)来模拟正则截取,或者使用用户自定义函数(UDF)来扩展功能。然而,由于用户权限问题(如之前遇到的执行权限问题),自定义函数可能不是最佳选择。 因此,我们考虑使用内置字符串函数组合实现。但请注意,这种方法只适用于简单的模式匹配,复杂的正则表达式可能难以实现。 以下是一些替代方案: 1. 使用SUBSTRING_INDEX函数:适用于分隔符固定的字符串。 2. 使用LOCATE或INSTR函数找到位置,再用SUBSTRING截取。 3. 如果模式是固定的(例如连续的数字),可以使用MID和字符串函数组合。 但是,如果必须使用正则表达式,且无法升级到MySQL 8.0,那么可能需要使用用户自定义函数(UDF)或者应用程序层处理(如在PHP、Python等语言中处理)。 由于问题中提到在MySQL 5.7中实现,且用户可能没有权限创建函数(参考之前的错误),这里重点介绍使用内置函数的方法。 示例:假设我们有一个字符串,要提取其中连续数字的部分。 方法1:使用字符串函数(适用于简单情况) 例如,从字符串'abc123def'中提取数字123。 步骤: - 找到第一个数字的位置:使用`LOCATE`函数结合数字字符集(0-9)逐个查找,但MySQL没有直接查找字符集的功能,所以我们需要用其他方法。 我们可以这样: - 使用`TRIM`函数去除非数字字符(但注意,TRIM只能去除两端,不能去除中间): ```sql SELECT TRIM(BOTH 'abcdefghijklmnopqrstuvwxyz' FROM 'abc123def') AS numbers; ``` 结果:'123' 但是,如果字符串是'abc123def456',上面的方法只能去除字母,得到'123456',不能分开两段数字。 方法2:使用SUBSTRING_INDEX和SUBSTRING_INDEX组合(适用于有分隔符的情况) 如果字符串有固定的分隔符,比如用逗号分隔,那么可以用SUBSTRING_INDEX。 方法3:使用自定义函数(需要权限) 如果内置函数无法满足,且用户有创建函数的权限,可以考虑使用自定义函数(UDF)来调用外部正则库(如PCRE)。但这种方法需要编译和安装,且需要MySQL服务器有文件系统权限,通常不推荐在共享环境中使用。 鉴于以上情况,对于MySQL 5.7,我们通常建议: - 如果需求简单,使用内置字符串函数组合。 - 如果需求复杂,考虑在应用程序层处理(如使用编程语言的正则表达式功能)。 - 升级到MySQL 8.0,使用内置的REGEXP_SUBSTR函数。 由于我们没有具体的字符串示例,这里给出一个通用的使用字符串函数提取数字的示例(假设数字在字符串中间,且没有其他数字): 示例:提取字符串'abc123def'中的数字 ```sql SELECT SUBSTRING('abc123def', (SELECT position FROM ( SELECT MIN(IF(ASCII(SUBSTRING('abc123def', n, 1)) BETWEEN 48 AND 57, n, NULL)) AS position FROM (SELECT 1 AS n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10) numbers WHERE n <= LENGTH('abc123def') ) AS t ), (SELECT length FROM ( SELECT COUNT(*) AS length FROM (SELECT 1 AS n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10) numbers WHERE n <= LENGTH('abc123def') AND ASCII(SUBSTRING('abc123def', n, 1)) BETWEEN 48 AND 57 AND n >= (SELECT MIN(IF(ASCII(SUBSTRING('abc123def', n, 1)) BETWEEN 48 AND 57, n, NULL)) ) AS t2 ) ) AS extracted_number; ``` 这个查询非常复杂,而且需要预先知道字符串的最大长度(这里假设10以内,所以用了1到10的序列)。对于长字符串,我们需要一个数字序列表(或者使用动态生成序列的方法,但MySQL没有生成序列的函数,通常需要预先生成)。 因此,在实际使用中,这种方法效率低下且复杂,不推荐。 结论:对于MySQL 5.7,如果无法使用自定义函数且无法升级到8.0,建议在应用程序中处理正则表达式提取。 如果必须使用MySQL,且需要处理复杂的正则表达式,可以考虑使用以下方法: 1. 创建一个辅助表,存储足够多的数字序列(例如1到10000)。 2. 使用这个数字序列来拆分字符串的每个字符,然后过滤出符合正则规则的连续字符(但注意,用SQL实现正则规则匹配同样复杂)。 鉴于以上困难,我们建议在MySQL 5.7中避免使用正则表达式截取,除非情况非常简单。 如果您的需求是提取固定格式的字符串(如邮箱、电话等),请提供具体示例,我们可以尝试用字符串函数组合实现。 注意:MySQL 5.7支持REGEXP操作符进行匹配,但不支持提取子串。因此,我们可以使用REGEXP来判断是否匹配,但提取操作需要其他函数。 例如,提取第一个连续数字: ```sql SELECT SUBSTRING( 'abc123def', PATINDEX('%[0-9]%', 'abc123def'), -- 但是MySQL没有PATINDEX函数,这是SQL Server的函数 LOCATE('a', 'abc123def') -- 同样,MySQL没有直接找到第一个数字位置的内置函数 ); ``` 实际上,MySQL没有类似于PATINDEX的函数。所以,我们只能使用前面提到的复杂方法。 因此,我们再次强调,在MySQL 5.7中,如果没有自定义函数,提取任意正则表达式匹配的子串是非常困难的。 建议: - 升级到MySQL 8.0,使用REGEXP_SUBSTR函数。 - 在应用程序中处理。 - 如果数据在数据库中且必须用SQL,创建存储函数(需要权限)来实现简单的模式匹配(例如,循环遍历字符串,找到第一个数字开始的位置和长度,然后截取)。 由于之前用户遇到权限问题,创建存储函数可能不可行。 所以,我们提供一种使用存储函数的思路(如果权限允许): ```sql DELIMITER $$ CREATE FUNCTION regexp_extract(s VARCHAR(255), pattern VARCHAR(255)) RETURNS VARCHAR(255) DETERMINISTIC BEGIN DECLARE position INT; DECLARE length INT; -- 这里需要实现正则匹配逻辑,但MySQL 5.7存储函数不支持正则表达式操作(除了REGEXP操作符,但无法获取位置) -- 因此,即使创建存储函数,我们仍然难以实现复杂的正则匹配。 -- 所以,这个方法实际上不可行。 RETURN NULL; END$$ DELIMITER ; ``` 综上所述,对于MySQL 5.7,我们无法直接使用内置函数实现正则表达式截取。建议在应用层处理。 如果您的需求是提取特定模式的字符串(例如,两个特定字符之间的字符串),我们可以用字符串函数实现。例如,提取括号内的字符串: ```sql SELECT SUBSTRING(column, LOCATE('(', column) + 1, LOCATE(')', column) - LOCATE('(', column) - 1 ) FROM table; ``` 请提供具体的提取需求,以便我们给出更精确的解决方案。 引用说明: [1]中提到MySQL的字符串截取函数(left, right, substring等),我们可以组合使用这些函数。 [2]中提到的正则表达式匹配(REGEXP操作符)只能用于匹配,不能提取。 [3]中提到的regexp_instr是MySQL 8.0才引入的函数。 因此,在MySQL 5.7中,我们只能使用非正则的方法进行字符串提取。 §§相关问题§§ 1. MySQL 5.7中如何提取字符串中的数字? 2. MySQL 8.0的正则表达式函数有哪些? 3. 如何在MySQL中创建数字辅助表? 4. 如何升级MySQL 5.7到8.0? 5. 在PHP中如何用正则表达式提取字符串?</think>在 MySQL 5.7 中实现正则表达式截取字符串功能需要特别注意,因为该版本原生**不支持**类似 `REGEXP_SUBSTR()` 的正则提取函数(这是 MySQL 8.0+ 的功能)。以下是 MySQL 5.7 中可用的替代方案: ### 一、MySQL 5.7 原生解决方案 #### 1️⃣ **字符串函数组合**(推荐) 结合内置字符串函数模拟正则截取: ```sql -- 示例:提取 "订单号: ABC-123-2023" 中的 "123" SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('订单号: ABC-123-2023', '-', 2), '-', -1) AS result; -- 结果: 123 ``` 常用函数组合: - `SUBSTRING(str, pos, len)`:基础截取 - `SUBSTRING_INDEX(str, delim, count)`:按分隔符截取 - `LOCATE(substr, str)`:定位子串位置 - `REPLACE(str, from_str, to_str)`:替换内容 #### 2️⃣ **REGEXP + 字符串函数**(仅匹配) 可检测匹配但无法直接提取子串: ```sql -- 检查是否匹配模式 SELECT 'abc123def' REGEXP '[0-9]{3}'; -- 返回 1(真) ``` ### 二、高级替代方案 #### 1️⃣ **创建自定义函数**(需权限) 实现类似 `REGEXP_SUBSTR` 的功能: ```sql DELIMITER $$ CREATE FUNCTION regexp_extract(str TEXT, pattern TEXT) RETURNS TEXT DETERMINISTIC BEGIN DECLARE i INT DEFAULT 1; WHILE i <= LENGTH(str) DO IF SUBSTRING(str, i) REGEXP CONCAT('^', pattern) THEN RETURN SUBSTRING(str, i, PATINDEX(SUBSTRING(str, i), pattern) -- 伪代码需实际实现 ); END IF; SET i = i + 1; END WHILE; RETURN NULL; END$$ DELIMITER ; ``` > ⚠️ 需 `CREATE ROUTINE` 权限,且需完整实现模式匹配逻辑 #### 2️⃣ **应用层处理**(推荐) 在应用程序中处理更高效: ```python # Python 示例 import re data = cursor.execute("SELECT raw_text FROM table") for row in data: result = re.search(r'(\d{3}-\d{4})', row[0]) print(result.group(1) if result else None) ``` ### 三、MySQL 8.0+ 的现代方案(升级建议) 若升级到 MySQL 8.0,可直接使用: ```sql -- 提取第一个匹配项 SELECT REGEXP_SUBSTR('电话: 010-1234-5678', '[0-9]{3}-[0-9]{4}') AS phone_part; -- 结果: 123-4567 -- 提取特定捕获组 SELECT REGEXP_SUBSTR('date: 2023-12-31', '([0-9]{4})-([0-9]{2})', 1, 1, '', 2) AS month; -- 结果: 12 ``` ### 四、使用建议 | 方案 | 适用场景 | 复杂度 | |---------------------|---------------------------------|-------| | 字符串函数组合 | 简单固定模式 | ★☆☆ | | 应用层处理 | 复杂正则/无数据库权限 | ★★☆ | | 自定义函数 | 高频使用/不能改应用代码 | ★★★ | | 升级到 MySQL 8.0 | 长期项目/新系统 | ★★☆ | > 📌 **关键结论**:MySQL 5.7 原生缺乏正则提取功能,建议: > 1. 简单场景用 `SUBSTRING` + `LOCATE` 组合 > 2. 复杂场景在应用层处理 > 3. 重要项目考虑升级到 MySQL 8.0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值