您现在的位置是:首页 > cms教程 > Discuz教程Discuz教程
discuz和ecshop截取字符串函数介绍
妙菡2025-07-04Discuz教程已有人查阅
导读网上看到一篇文章 discuz和ecshop截取字符串的两个函数,比较了一下两个版本的函数,都各有局限,只能在特定的前提下使用,但是学习一下有利于拓宽思路,了解PHP的扩展功能。
网上看到一篇文章 discuz和ecshop截取字符串的两个函数,比较了一下两个版本的函数,都各有局限,只能在特定的前提下使用,但是学习一下有利于拓宽思路,了解PHP的扩展功能。
下面先给出两个版本函数的源代码以及简单测试,之后我会给出一个实用性更强的字符串截取函数。需要注意的是:这里讨论的字符串截取问题都是针对UTF-8编码的中文字符串。
discuz版本
ecshop版
截取中文字符串的大部分应用场景是“原始字符串可以是中文、英文、数字混杂的,中文字按2个字符算,英文数字按1个字符算”,针对这个需求下面给出一个实现版本:
下面先给出两个版本函数的源代码以及简单测试,之后我会给出一个实用性更强的字符串截取函数。需要注意的是:这里讨论的字符串截取问题都是针对UTF-8编码的中文字符串。
discuz版本
1 /**
2 * [discuz] 基于PHP没有安装 mb_substr 等扩展截取字符串,如果截取中文字则按2个字符计算
3 * @param $string 要截取的字符串
4 * @param $length 要截取的字符数
5 * @param $dot 替换截掉部分的结尾字符串
6 * @return 返回截取后的字符串
7 */
8 function cutstr($string, $length, $dot = '...') {
9 // 如果字符串小于要截取的长度则直接返回
10 // 此处使用strlen获取字符串长度有很大的弊病,比如对字符串“新年快乐”要截取4个中文字符,
11 // 那么必须知道这4个中文字符的字节数,否则返回的字符串可能会是“新年快乐...”
12 if (strlen($string) <= $length) {
13 return $string;
14 }
15
16 // 转换原字符串中htmlspecialchars
17 $pre = chr(1);
18 $end = chr(1);
19 $string = str_replace ( array ('&', '"', '<', '>' ), array ($pre . '&' . $end, $pre . '"' . $end, $pre . '<' . $end, $pre . '>' . $end ), $string );
20
21 $strcut = ''; // 初始化返回值
22
23 // 如果是utf-8编码(这个判断有点不全,有可能是utf8)
24 if (strtolower ( CHARSET ) == 'utf-8') {
25 // 初始连续循环指针$n,之后一个字位数$tn,截取的字符数$noc
26 $n = $tn = $noc = 0;
27 while ( $n < strlen ( $string ) ) {
28 $t = ord ( $string [$n] );
29
30 if ($t == 9 || $t == 10 || (32 <= $t && $t <= 126)) {
31 // 如果是英语半角符号等,$n指针后移1位,$tn之后字是1位
32 $tn = 1;
33 $n++;
34 $noc++;
35 } elseif (194 <= $t && $t <= 223) {
36 // 如果是二字节字符$n指针后移2位,$tn之后字是2位
37 $tn = 2;
38 $n += 2;
39 $noc += 2;
40 } elseif (224 <= $t && $t <= 239) {
41 // 如果是三字节(可以理解为中字词),$n后移3位,$tn之后字是3位
42 $tn = 3;
43 $n += 3;
44 $noc += 2;
45 } elseif (240 <= $t && $t <= 247) {
46 $tn = 4;
47 $n += 4;
48 $noc += 2;
49 } elseif (248 <= $t && $t <= 251) {
50 $tn = 5;
51 $n += 5;
52 $noc += 2;
53 } elseif ($t == 252 || $t == 253) {
54 $tn = 6;
55 $n += 6;
56 $noc += 2;
57 } else {
58 $n++;
59 }
60
61 // 超过了要取的数就跳出连续循环
62 if ($noc >= $length) {
63 break;
64 }
65 }
66
67 // 这个地方是把之后一个字去掉,以备加$dot
68 if ($noc > $length) {
69 $n -= $tn;
70 }
71
72 $strcut = substr ( $string, 0, $n );
73
74 } else {
75 // 并非utf-8编码的全角就后移2位
76 for ($i = 0; $i < $length; $i ++) {
77 $strcut .= ord ( $string [$i] ) > 127 ? $string [$i] . $string [++ $i] : $string [$i];
78 }
79 }
80
81 // 再还原最初的htmlspecialchars
82 $strcut = str_replace( array ($pre . '&' . $end, $pre . '"' . $end, $pre . '<' . $end, $pre . '>' . $end ), array ('&', '"', '<', '>' ), $strcut );
83
84 $pos = strrpos ( $strcut, chr ( 1 ) );
85 if ($pos !== false) {
86 $strcut = substr ( $strcut, 0, $pos );
87 }
88
89 return $strcut . $dot; // 之后把截取加上$dot输出
90 }
discuz版本的较大缺陷在于使用 strlen 获取原始字符串的长度,并用来和传入的要截取长度参数(字节数)进行比较,由于UTF-8的中文字符的字节数是不固定的,所以就会面临这样的窘境:如果要截取4个中文字符应该指定多大的截取长度呢?8字节还是12字节呢?这是无法预计的,也正是因为这个问题discuz的cutstr实际是有bug的,通过下面的测试结果能看出:
$str1 = "欲穷千里目";
echo my_cutstr($str1, 10, "...")."\n"; // 输出:欲穷千里目... [这是一个bug,想想是什么原因导致?]
echo my_cutstr($str1, 15, "...")."\n"; // 输出:欲穷千里目
导致上述bug的原因在与cutstr函数在截取字符的时候是将一个中文字按2个字符算,那么5个中文字就是10字符,而原始字符串的长度是15字节,所以cutstr认为“成功地”从15字符的串上截取了10个字符,然后加上了“尾巴”。要解决这个bug只要在判断一下返回的子串是否和原始串相同,如果相同就不加“尾巴”。ecshop版
1 /**
2 * [ecshop] 基于PHP的 mb_substr,iconv_substr 这两个扩展来截取字符串,中文字符都是按1个字符长度计算;
3 * 该函数仅适用于utf-8编码的中文字符串。
4 *
5 * @param $str 原始字符串
6 * @param $length 截取的字符数
7 * @param $append 替换截掉部分的结尾字符串
8 * @return 返回截取后的字符串
9 */
10 function sub_str($str, $length = 0, $append = '...') {
11 $str = trim($str);
12 $strlength = strlen($str);
13
14 if ($length == 0 || $length >= $strlength) {
15 return $str;
16 } elseif ($length < 0) {
17 $length = $strlength + $length;
18 if ($length < 0) {
19 $length = $strlength;
20 }
21 }
22
23 if ( function_exists('mb_substr') ) {
24 $newstr = mb_substr($str, 0, $length, 'utf-8');
25 } elseif ( function_exists('iconv_substr') ) {
26 $newstr = iconv_substr($str, 0, $length, 'utf-8');
27 } else {
28 //$newstr = trim_right(substr($str, 0, $length));
29 $newstr = substr($str, 0, $length);
30 }
31
32 if ($append && $str != $newstr) {
33 $newstr .= $append;
34 }
35
36 return $newstr;
37 }
ecshop版的特点和缺点都在于将中文字符算作一个字符,如果原始字符串中不含中文,比如:abcd1234,如果本意是要截取4个中文字符或者8个英文字符,那么使用ecshop的版本就得不到期望的结果,返回值的是:abcd。下面是简单的测试结果:
$str1 = "白日依山尽,黄河入海流";
echo $str1."\n";
echo my_sub_str($str1, 4, "...")."\n"; // 输出:白日依山...
$str2 = "白1日2依3山4";
echo $str2."\n";
echo my_sub_str($str2, 4, "...")."\n"; // 输出:白1日2...
优化版截取中文字符串的大部分应用场景是“原始字符串可以是中文、英文、数字混杂的,中文字按2个字符算,英文数字按1个字符算”,针对这个需求下面给出一个实现版本:
1 /**
2 * 字符串截取,中文字符按2个字符计算,同时支持GBK和UTF-8编码
3 * @param $string 要截取的字符串
4 * @param $length 要截取的字符数
5 * @param $append 添加到子串后的尾巴
6 * @return 返回截取后的字符串
7 */
8 function substring($string, $length, $append = false) {
9 if ( $length <= 0 ) {
10 return '';
11 }
12
13 // 检测原始字符串是否为UTF-8编码
14 $is_utf8 = false;
15 $str1 = @iconv("UTF-8", "GBK", $string);
16 $str2 = @iconv("GBK", "UTF-8", $str1);
17 if ( $string == $str2 ) {
18 $is_utf8 = true;
19
20 // 如果是UTF-8编码,则使用GBK编码的
21 $string = $str1;
22 }
23
24 $newstr = '';
25 for ($i = 0; $i < $length; $i ++) {
26 $newstr .= ord ($string[$i]) > 127 ? $string[$i] . $string[++$i] : $string[$i];
27 }
28
29 if ( $is_utf8 ) {
30 $newstr = @iconv("GBK", "UTF-8", $newstr);
31 }
32
33 if ($append && $newstr != $string) {
34 $newstr .= $append;
35 }
36
37 return $newstr;
38 }
测试结果见下(GBK和UTF-8的结果一致):
$str1 = "白日依山尽,黄河入海流";
echo substring($str1, 4, "...")."\n"; // 输出:白日...
echo substring($str1, 5, "...")."\n"; // 输出:白日依...
$str2 = "12白34日56依78山";
echo substring($str2, 4, "...")."\n"; // 输出:12白...
echo substring($str2, 5, "...")."\n"; // 输出:12白3...
本文标签:
很赞哦! ()
相关教程
- jQuery trim()方法:轻松清理字符串首尾空白
- jQuery param()方法:将对象或数组序列化为查询字符串
- JavaScript Number.toString()方法:数值转字符串与进制转换的桥梁
- JavaScript Number.parseInt()方法解析:字符串转整数的规则与实战
- JavaScript Number.parseInt()方法:将字符串解析为整数
- JavaScript Number.parseFloat()方法:从字符串中提取浮点数
- JavaScript字符串模板
- JavaScript字符串
- phpcms-v9自带的字符串截取函数的方法
- PbootCMS使用substr参数截取字符串的方法
- ecshop模板截取字符串的实现方法
- discuz和ecshop的截取字符串函数对比分析
图文教程
阿里云OSS搭建discuz步骤教程
discuz 使用阿里云OSS说明:我绑定了二级域名,本演示采用二级域名oss来介绍,我实际使用的是二级域名pic。新手第一次分享使用经验,望各位大神手下留情...
discuz注册账号的方法步骤
注册 Discuz 账号的步骤:1. 访问 Discuz 官网;2. 点击“注册”按钮;3. 填写注册信息,包括用户名、密码、邮箱地址等;4. 同意条款和隐私政策;5. 点击“注册”按钮;6. 账号;7. 使用用户名和密码登录论坛。
Discuz首页四格插件使用方法
第一步:上传相关文件:包含文件:pic.php 请上传至论坛根目录images目录 请将目录下的文件(两个图片一个FLASH)上传到论坛images目录下第二步:修改index.php(修改前请先备份,出错时可以恢复)
Discuz二次开发文件目录结构说明
一) Discuz!的文件系统目录注:想搞DZ开发,就得弄懂DZ中每个文件的功能。a) Admin:后台管理功能模块b) Api:DZ系统与其它系统之间接口程序
相关源码
-
(PC+手机)帝国cms7.5漫画图片连载网站源码免费下载本模板基于帝国CMS7.5深度开发,为漫画阅读类网站打造。整体设计风格贴合漫画行业特性,界面布局充分考虑漫画作品的展示需求,支持多种漫画阅读模式。模板采用响应式设计,能够自动适配PC端和移动端设备,为读者提供流畅的阅读体验。查看源码 -
(自适应响应式)蓝色律师事务所法务团队网站pbootcms模板为律师事务所和法律服务机构打造的专业网站模板,展现法律专业性与权威性,手工编写标准DIV+CSS代码,结构清晰优化,确保高效运行,自动适配电脑、平板和手机等各类设备,提供更好浏览体验查看源码 -
(PC+WAP)绣花刺绣传统手工工艺pbootcms网站源码下载这款基于PbootCMS的网站模板为刺绣和传统手工艺行业设计,采用优雅的布局和精致的细节处理,能够呈现手工艺品的独特韵味和文化内涵。模板结构合理,功能完善,是手工艺从业者展示作品的理想选择。查看源码 -
(PC+WAP)智能机器人人工智能物联网自动化设备源码下载本模板基于PbootCMS内核开发,为智能机器人及传感器科技企业精心设计。采用现代化设计风格,突出科技感与专业性,多方位展示企业技术实力与产品优势。查看源码 -
自适应LED照明外贸灯具灯泡灯具英文网站模板该外贸灯具网站模板专为LED照明、灯具出口企业定制,采用PbootCMS内核开发,提供高效建站方案。通过响应式设计和SEO优化能力,帮助企业低成本构建专业外贸展示平台。查看源码 -
(自适应响应式)陶瓷研磨盘抛光机械设备pbootcms网站模板本模板基于PbootCMS系统开发,为研磨抛光设备制造企业设计,特别适合陶瓷研磨盘、抛光设备等表面处理设备展示。采用响应式布局技术,确保各类设备的参数和工艺在不同终端上都能清晰呈现。查看源码
| 分享笔记 (共有 篇笔记) |
