mb_substr

(PHP 4 >= 4.0.6, PHP 5, PHP 7, PHP 8)

mb_substr获取字符串的一部分

描述

mb_substr(
    string $string,
    int $start,
    ?int $length = null,
    ?string $encoding = null
): string

根据字符数量执行安全的 substr() 多字节操作。位置从 string 的开头算起。第一个字符的位置为 0。第二个字符的位置为 1,依此类推。

参数

string

要从中提取子字符串的 string

start

如果 start 为非负数,则返回的字符串将从 string 中的第 start 个位置开始,从零开始计数。例如,在字符串 'abcdef' 中,位置 0 处的字符为 'a',位置 2 处的字符为 'c',依此类推。

如果 start 为负数,则返回的字符串将从 string 结尾的第 start 个字符开始。

length

string 中使用的最大字符数。如果省略或传递 NULL,则提取到字符串结尾的所有字符。

encoding

encoding 参数是字符编码。如果省略或为 null,则使用内部字符编码值。

返回值

mb_substr() 返回由 startlength 参数指定的 string 的部分。

变更日志

版本 描述
8.0.0 encoding 现在可以为空。

参见

添加备注

用户贡献的备注 10 个备注

11
qbolec at gmail dot com
9 年前
由于您经常需要在字符串中迭代 UTF-8 字符,因此您可能会倾向于使用 mb_substr($text,$i,1)。
这样做的问题是,除了从开头逐字节读取之外,没有“神奇”的方法来查找 UTF-8 字符串中的第 $i 个字符。因此,一个对所有可能的 $i 值调用 mb_substr($text,$i,1) N 次的循环,将比预期的花费更长时间。$i 越大,搜索第 $i 个字母的时间就越长。由于字符的长度在 1 到 6 字节之间,所以我们可以相信,这种循环的执行时间实际上是 Theta(N^2),即使对于中等长度的文本,这也会非常慢。
一种解决方法是首先使用一些智能预处理将您的文本拆分为字母数组,然后再迭代该数组。
这是一个想法
<?php
class Strings
{
public static function
len($a){
return
mb_strlen($a,'UTF-8');
}
public static function
charAt($a,$i){
return
self::substr($a,$i,1);
}
public static function
substr($a,$x,$y=null){
if(
$y===NULL){
$y=self::len($a);
}
return
mb_substr($a,$x,$y,'UTF-8');
}
public static function
letters($a){
$len = self::len($a);
if(
$len==0){
return array();
}else if(
$len == 1){
return array(
$a);
}else{
return
Arrays::concat(
self::letters(self::substr($a,0,$len>>1)),
self::letters(self::substr($a,$len>>1))
);
}
}
?>
如您所见,Strings::letters($text) 将文本递归地拆分为两部分。每次递归都需要花费与字符串长度成线性关系的时间,并且递归级别是对数级的,因此总运行时间为 O(N log N),这仍然比理论上的最佳 O(N) 更长,但遗憾的是,这是我想到的最佳方法。
5
drraf at tlen dot pl
19 年前
注意:如果边界超出了字符串 - mb_string() 返回空 _字符串_,而函数 substr() 在这种情况下返回 _布尔_ false。
使用“===”比较时请牢记这一点。

示例代码
<?php

var_dump
( substr( 'abc', 5, 2 ) ); // 返回 "false"
var_dump( mb_substr( 'abc', 5, 2 ) ); // 返回 ""

?>

在函数重载打开的情况下,使用 mbstring 时尤其令人困惑。
3
p dot assenov at aip-solutions dot com
12 年前
我正在尝试只将字符串的第一个字符大写,并尝试了一些上面的示例,但它们不起作用。似乎 mb_substr() 无法在多字节编码(UTF-8)中计算字符串的长度,并且应该明确设置。以下是修正后的版本

<?php
function mb_ucfirst($str, $enc = 'utf-8') {
return
mb_strtoupper(mb_substr($str, 0, 1, $enc), $enc).mb_substr($str, 1, mb_strlen($str, $enc), $enc);
}
?>

干杯!
4
xiaogil at yahoo dot fr
19 年前
感谢来自 /freenode #php 的 Darien 提供了以下示例(稍微修改了一下)。

它只是打印了 $string 的第 6 个字符。
你可以用日语、中文或任何其他语言的数字替换这些数字进行测试,它运行完美。

<?php
mb_internal_encoding
("UTF-8");
$string = "0123456789";
$mystring = mb_substr($string,5,1);
echo
$mystring;
?>

(例如,我无法用中文数字替换 0123456789,因为该网站会自动将其转换为拉丁数字,请看
&#38646;&#19968;&#20108;&#19977;&#22235;
&#20116;&#20845;&#19971;&#20843;&#20061;)

gilv
0
public at luedi dot jp
4 个月前
只想补充一点,不仅 `start` 可以是负数,`length` 也可以是负数。并且按预期工作。

mb_substr( "1234567890", 3, -4, "UTF-8" ) => "456".

因此它截掉了最后 4 个字符。
0
boulahdidraid18 at gmail dot com
7 个月前
以下示例演示了 `substr` 和 `mb_substr` 函数之间的区别

1- 当处理非 UTF-8 字符时,这两个函数的行为相同,并提供相同的输出

$str = 'abcdef';
echo substr($s, 0, 3); // abc
echo mb_substr($s, 0, 3); // abc

2- 当处理 UTF-8 字符时,每个函数的行为将不同,并提供不同的结果

2.A- `substr` 函数在字节级工作,并且仅适用于单字节编码的字符(不支持多字节编码)。

例如

$str_utf8 = utf8_encode("déjà_vu");

如果我们这样做

echo substr($str_utf8, 0, 3); // dé
echo substr($str_utf8, 0, 2); // d�

=> 这是因为特殊字符 "é"(和 "à")在内部用两个字节编码

PHP 将从索引 0 开始读取第一个字节,它表示 `d`,然后移动到第二个字节,它属于字符 `é` 的两个字节编码的一部分,并且由于长度设置为 2,PHP 将在此处停止,不会继续读取第三个字节,因此它无法识别字符 `é`,并打印 � 而不是 é。

2.B- `mb_substr` 函数在字符级工作,并支持多字节编码的字符。这意味着 PHP 仅统计字符数量,而不考虑其编码的字节数,例如

$str_utf8 = utf8_encode("déjà_vu");

echo mb_substr($str_utf8, 0, 4, "UTF-8"); // Déjà
echo mb_substr($str_utf8, 1, 4, "UTF-8"); // éjà_
echo mb_substr($str_utf8, 6, 4, "UTF-8"); // u
echo mb_substr($str_utf8, 7, 4, "UTF-8"); // ''
echo mb_substr($str_utf8, -2, "UTF-8"); // vu
echo mb_substr($str_utf8, -2, 1, "UTF-8"); // v
echo mb_substr($str_utf8, -2, 3, "UTF-8"); // vu
0
desmatic at gmail dot com
11 年前
快速且肮脏的遍历多字节字符串循环
<?php
function get_character_classes($string, $encoding = "UTF-8") {
$current_encoding = mb_internal_encoding();
mb_internal_encoding($encoding);
$has = array();
$stringlength = mb_strlen($string, $encoding);
for (
$i=0; $i < $stringlength; $i++) {
$c = mb_substr($string, $i, 1);
if ((
$c >= "0") && ($c <= "9")) {
$has['numeric'] = "numeric";
} else if ((
$c >= "a") && ($c <= "z")) {
$has['alpha'] = "alpha";
$has['alphalower'] = 'alphalower';
} else if ((
$c >= "A") && ($c <= "Z")) {
$has['alpha'] = "alpha";
$has['alphaupper'] = "alphaupper";
} else if ((
$c == "$") || ($c == "£")) {
$has['currency'] = "currency";
} else if ((
$c == ".") && ($has['decimal'])) {
$has['decimals'] = "decimals";
} else if (
$c == ".") {
$has['decimal'] = "decimal";
} else if (
$c == ",") {
$has['comma'] = "comma";
} else if (
$c == "-") {
$has['dash'] = "dash";
} else if (
$c == " ") {
$has['space'] = "space";
} else if (
$c == "/") {
$has['slash'] = "slash";
} else if (
$c == ":") {
$has['colon'] = "colon";
} else if ((
$c >= " ") && ($c <= "~")) {
$has['ascii'] = "ascii";
} else {
$has['binary'] = "binary";
}
}
mb_internal_encoding($current_encoding);

return
$has;
}

$string = "1234asdfA£^_{}|}~žščř";
echo
print_r(get_character_classes($string), true);
?>

数组
(
[numeric] => numeric
[alpha] => alpha
[alphalower] => alphalower
[alphaupper] => alphaupper
[currency] => currency
[ascii] => ascii
[binary] => binary
)
-3
sanjuro at 1up-games dot com
10 年前
在使用设置为 HTML-ENTITIES 编码的 mb_substr() 时,一个严重的陷阱是该函数在返回该值之前执行了许多转换,其中最糟糕的是 HTML 特殊字符不仅被统计,而且被解码。

<?php

mb_internal_encoding
("ISO-8859-1"); echo mb_internal_encoding(),"\n<br><br>\n";

$a='j&uuml;st &#228; &quot; simple &quot; &#26085;&#26412; &lt;b&gt;test&lt;/b&gt;';

echo
mb_substr($a,0),"\n<br><br>\n";
// 页面源代码: j&uuml;st &#228; &quot; simple &quot; &#26085;&#26412; &lt;b&gt;test&lt;/b&gt;

echo mb_substr($a,0,strlen($a),'HTML-ENTITIES');
// 页面源代码: j&uuml;st &auml; " simple " &#26085;&#26412; <b>test</b>

?>
-5
qdinar at gmail dot com
8 年前
你可以使用 ucs-2 编码使 mb_substr 在处理长字符串时运行得更快。

<?php

header
('Content-Type: text/html; charset=utf-8');
echo
'<meta http-equiv="Content-Type" content="text/html; charset=utf-8" >';

function
test($string, $encoding='utf8'){
$t1=microtime(true);
$textlen=mb_strlen($string);
$substr_len=3;
for(
$i=0;$i<$textlen-$substr_len+1;$i++){
$substr=mb_substr($string,$i,$substr_len);
}
echo
'mb_substr, '.$encoding.': '.(microtime(true)-$t1);
echo
' . check: ';
if(
$encoding=='ucs2'){
$substr=mb_convert_encoding($substr,'utf-8','ucs2');
}
var_dump( $substr );
echo
' . <br>';
echo
'<br>';
}

$corpus_short=str_repeat('тест Тест ',1000);
// it works likewise slowly with "test Test" with utf8
mb_internal_encoding('utf-8');
test($corpus_short);

$corpus_short_ucs2=mb_convert_encoding($corpus_short,'ucs2','utf-8');
mb_internal_encoding('ucs2');
test($corpus_short_ucs2,'ucs2');

?>

输出

mb_substr, utf8: 0.26480984687805 . check: string(5) "ст " .

mb_substr, ucs2: 0.0048871040344238 . check: string(5) "ст " .
-16
projektas at gmail dot com
15 年前
首字母大写 <hr />

<?php
header
('Content-type: text/html; charset=utf-8');

if (isset(
$_POST['check']) && !empty($_POST['check'])) {
echo
htmlspecialchars(ucfirst_utf8($_POST['check']));
} else {
echo
htmlspecialchars(ucfirst_utf8('Žąsinų'));
}

function
ucfirst_utf8($str) {
if (
mb_check_encoding($str,'UTF-8')) {
$first = mb_substr(
mb_strtoupper($str, "utf-8"),0,1,'utf-8'
);
return
$first.mb_substr(
mb_strtolower($str,"utf-8"),1,mb_strlen($str),'utf-8'
);
} else {
return
$str;
}
}
?>

<form method="post" action="" >
<input type="input" name="check" />
<input type="submit" />
</form>
To Top