PHP 实现中文字符串截取无乱码
题目如标题所示,上次我在PHP 一个函数实现字符串反转吐槽了一个悲伤的故事叫做不支持中文,这次终于会用中文支持了,所以其实我写的是反转的第二版
这次用了两种方法,第一种是正则表达式,其实我还不会用正则……嗯……除了最简单的。
function reverse($str) {
$pattern = '/./us';
preg_match_all($pattern, $str, $matches);
$str = array_reverse($matches[0]);
$str = implode($str);
return $str;
}
/./us
,/
是分隔符,正则表达式必须写在这两个之间,和html闭合标签是一个原理的,.
代表除了换行符的所有字符,而s
使换行符也包括了进去
之后再用preg_match_all()
他会把所有符合的打散到数组,第一个是正则表达式,第二个参数是字符串,第三个参数是要打入的数组(可以不要)。打散之后数组中所有元素用$matches[0]
输出,第一个匹配的元素用$matches[1]
,以此类推(PS:如果是preg_match
那么第一个匹配后就会停止匹配了)
然后array_reverse()
,可以返回一个单元顺序相反的数组,之后合并为字符串就行了。array_reverse()
的扩展阅读:http://www.php.net/manual/zh/function.array-reverse.phpimplode
扩展阅读:http://www.php.net/manual/zh/function.implode.php
第二种是用了utf-8编码的特性:
function reverse_utf($str) {
$len = strlen($str);
$arr = array();
for ($i = 0; $i < $len; ) {
$rune_len = 0;
$ch = ord($str[$i]);
for ($j = 7; $j >=2; $j--) {
if ($ch & (1 << $j))
$rune_len++;
else
break;
}
if ($rune_len == 0)
$rune_len = 1;
$arr[] = substr($str, $i, $rune_len);
$i += $rune_len;
}
$str = implode(array_reverse($arr));
return $str;
}
其实这段我自己也没怎么看懂OTZ每次都是一副好不容易看懂的样子。
首先来了解一下utf-8:
UTF-8 编码中每个字符的长度是看字符首字节高位的
比如某个字符第一个字节ASCII是110xxxxx
说明这个字符占两个字节1110xxxx
说明这个字符占三个字节
首先strlen
获取字符串的长度,ord
返回字符的ASCII码,位运算符检测这一位是不是1,因为2^0是1 2^1是10以此类推,也就是说如果此为是1 那么rune_len
会加1(用于判断字节长度)
完整源码:
<!DOCTYPE html>
<html>
<head>
<title>Reverse - V2</title>
</head>
<body>
<form action="reverse_v2.php" method="post">
<input type="text" name="str" placeholder="请输入字符">
<input type="submit" value="提交">
</form>
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$problem = FALSE;
$str = $_POST['str'];
if ( empty($str) ) {
$problem = TRUE;
echo '请输入字符';
}
if (!$problem) {
$origin = $str;
$result = reverse_utf($str);
echo '原始:' . $origin . '<br/>';
echo '结果:' . $result . '<br/>';
}
}
function reverse($str) {
$pattern = '/./us';
preg_match_all($pattern, $str, $matches);
$str = array_reverse($matches[0]);
$str = implode($str);
return $str;
}
function reverse_utf($str) {
$len = strlen($str);
$arr = array();
for ($i = 0; $i < $len; ) {
$rune_len = 0;
$ch = ord($str[$i]);
for ($j = 7; $j >=2; $j--) {
if ($ch & (1 << $j))
$rune_len++;
else
break;
}
if ($rune_len == 0)
$rune_len = 1;
$arr[] = substr($str, $i, $rune_len);
$i += $rune_len;
}
$str = implode(array_reverse($arr));
return $str;
}
?>
</body>
</html><!DOCTYPE html>
<html>
植入部分
如果您觉得文章不错,可以通过赞助支持我。
如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。