为什么 strtolower 比 strtoupper 稍慢?
Why is strtolower slightly slower than strtoupper?
出于好奇,我做了一个实验。我想看看 strtolower()
和 strtoupper()
之间是否存在细微差别。我预计 strtolower()
在大多数小写字符串上会更快,反之亦然。我发现 strtolower()
在所有情况下都比较慢(尽管在您执行数百万次之前完全微不足道。)这是我的测试。
$string = 'hello world';
$start_time = microtime();
for ($i = 0; $i < 10000000; $i++) {
strtolower($string);
}
$timed = microtime() - $start_time;
echo 'strtolower ' . $string . ' - ' . $timed . '<br>';
用 hello world
、HELLO WORLD
和 Hello World
重复 strtolower()
和 strtoupper()
。 Here is the full gist. 我已经 运行 代码好几次了,一直得到大致相同的结果。这是下面的测试之一 运行。
strtolower hello world - 0.043829
strtoupper hello world - 0.04062
strtolower HELLO WORLD - 0.042691
strtoupper HELLO WORLD - 0.015475
strtolower Hello World - 0.033626
strtoupper Hello World - 0.017022
我相信 php-src github 中控制它的 C 代码在这里用于 strtolower() and here for strtoupper()
需要说明的是,这不会阻止我使用 strtolower()
。我只是想了解这里发生了什么。
为什么 strtolower()
比 strtoupper()
慢?
这主要取决于您当前使用的字符编码,但速度差异的主要原因是特殊字符的每个编码字符的大小。
For example, lowercase j with caron (ǰ) is represented as a single encoded character (U+01F0 LATIN SMALL LETTER J WITH CARON), but the corresponding uppercase character (J̌) is represented in Unicode as a sequence of two encoded characters (U+004A LATIN CAPITAL LETTER J + U+030C COMBINING CARON).
在 Unicode 字符索引中筛选更多数据将不可避免地花费更长的时间。
请记住,strtolower
使用您当前的语言环境,因此如果您的服务器使用的字符编码不支持 strtolower
特殊字符(例如 'Ê '), 它只是 return 特殊字符。 UTF-8 上的字符映射是设置的,可以通过 运行 mb_strtolower.
确认
也可以将属于 uppercase
类别的字符数与 lowercase
类别中的字符数进行比较,但这又取决于你的字符编码。
简而言之,strtolower
有一个更大的字符数据库,可以在检查字符是否为 uppercase
.
时将每个单独的字符串字符进行比较
代码的实现有几个非常细微的差异:
PHPAPI char *php_strtoupper(char *s, size_t len)
{
unsigned char *c, *e;
c = (unsigned char *)s;
e = (unsigned char *)c+len; <-- strtolower uses e = c+len;
while (c < e) {
*c = toupper(*c);
c++;
}
return s;
}
PHPAPI zend_string *php_string_toupper(zend_string *s)
{
unsigned char *c, *e;
c = (unsigned char *)ZSTR_VAL(s);
e = c + ZSTR_LEN(s);
while (c < e) {
if (islower(*c)) {
register unsigned char *r;
zend_string *res = zend_string_alloc(ZSTR_LEN(s), 0);
if (c != (unsigned char*)ZSTR_VAL(s)) {
memcpy(ZSTR_VAL(res), ZSTR_VAL(s), c - (unsigned char*)ZSTR_VAL(s));
}
r = c + (ZSTR_VAL(res) - ZSTR_VAL(s));
while (c < e) {
*r = toupper(*c);
r++;
c++;
}
*r = '[=10=]';
return res;
}
c++;
}
return zend_string_copy(s);
}
PHP_FUNCTION(strtoupper)
{
zend_string *arg; <-- strtolower uses zend_string *str;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(arg) <-- strtolower uses Z_PARAM_STR(str)
ZEND_PARSE_PARAMETERS_END();
RETURN_STR(php_string_toupper(arg)); <-- strtolower uses RETURN_STR(php_string_tolower(str));
}
对于 strtolower
PHPAPI char *php_strtolower(char *s, size_t len)
{
unsigned char *c, *e;
c = (unsigned char *)s;
e = c+len; <-- strtoupper uses e = (unsigned char *)c+len;
while (c < e) {
*c = tolower(*c);
c++;
}
return s;
}
PHPAPI zend_string *php_string_tolower(zend_string *s)
{
unsigned char *c, *e;
c = (unsigned char *)ZSTR_VAL(s);
e = c + ZSTR_LEN(s);
while (c < e) {
if (isupper(*c)) {
register unsigned char *r;
zend_string *res = zend_string_alloc(ZSTR_LEN(s), 0);
if (c != (unsigned char*)ZSTR_VAL(s)) {
memcpy(ZSTR_VAL(res), ZSTR_VAL(s), c - (unsigned char*)ZSTR_VAL(s));
}
r = c + (ZSTR_VAL(res) - ZSTR_VAL(s));
while (c < e) {
*r = tolower(*c);
r++;
c++;
}
*r = '[=11=]';
return res;
}
c++;
}
return zend_string_copy(s);
}
PHP_FUNCTION(strtolower)
{
zend_string *str; <-- strtoupper uses zend_string *arg;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(str) <-- strtoupper uses Z_PARAM_STR(arg)
ZEND_PARSE_PARAMETERS_END();
RETURN_STR(php_string_tolower(str)); <-- strtoupper uses RETURN_STR(php_string_tolower(arg));
}
这些微小差异是否足以影响那几纳秒的性能,我不知道....不确定为什么会有差异
出于好奇,我做了一个实验。我想看看 strtolower()
和 strtoupper()
之间是否存在细微差别。我预计 strtolower()
在大多数小写字符串上会更快,反之亦然。我发现 strtolower()
在所有情况下都比较慢(尽管在您执行数百万次之前完全微不足道。)这是我的测试。
$string = 'hello world';
$start_time = microtime();
for ($i = 0; $i < 10000000; $i++) {
strtolower($string);
}
$timed = microtime() - $start_time;
echo 'strtolower ' . $string . ' - ' . $timed . '<br>';
用 hello world
、HELLO WORLD
和 Hello World
重复 strtolower()
和 strtoupper()
。 Here is the full gist. 我已经 运行 代码好几次了,一直得到大致相同的结果。这是下面的测试之一 运行。
strtolower hello world - 0.043829
strtoupper hello world - 0.04062
strtolower HELLO WORLD - 0.042691
strtoupper HELLO WORLD - 0.015475
strtolower Hello World - 0.033626
strtoupper Hello World - 0.017022
我相信 php-src github 中控制它的 C 代码在这里用于 strtolower() and here for strtoupper()
需要说明的是,这不会阻止我使用 strtolower()
。我只是想了解这里发生了什么。
为什么 strtolower()
比 strtoupper()
慢?
这主要取决于您当前使用的字符编码,但速度差异的主要原因是特殊字符的每个编码字符的大小。
For example, lowercase j with caron (ǰ) is represented as a single encoded character (U+01F0 LATIN SMALL LETTER J WITH CARON), but the corresponding uppercase character (J̌) is represented in Unicode as a sequence of two encoded characters (U+004A LATIN CAPITAL LETTER J + U+030C COMBINING CARON).
在 Unicode 字符索引中筛选更多数据将不可避免地花费更长的时间。
请记住,strtolower
使用您当前的语言环境,因此如果您的服务器使用的字符编码不支持 strtolower
特殊字符(例如 'Ê '), 它只是 return 特殊字符。 UTF-8 上的字符映射是设置的,可以通过 运行 mb_strtolower.
也可以将属于 uppercase
类别的字符数与 lowercase
类别中的字符数进行比较,但这又取决于你的字符编码。
简而言之,strtolower
有一个更大的字符数据库,可以在检查字符是否为 uppercase
.
代码的实现有几个非常细微的差异:
PHPAPI char *php_strtoupper(char *s, size_t len)
{
unsigned char *c, *e;
c = (unsigned char *)s;
e = (unsigned char *)c+len; <-- strtolower uses e = c+len;
while (c < e) {
*c = toupper(*c);
c++;
}
return s;
}
PHPAPI zend_string *php_string_toupper(zend_string *s)
{
unsigned char *c, *e;
c = (unsigned char *)ZSTR_VAL(s);
e = c + ZSTR_LEN(s);
while (c < e) {
if (islower(*c)) {
register unsigned char *r;
zend_string *res = zend_string_alloc(ZSTR_LEN(s), 0);
if (c != (unsigned char*)ZSTR_VAL(s)) {
memcpy(ZSTR_VAL(res), ZSTR_VAL(s), c - (unsigned char*)ZSTR_VAL(s));
}
r = c + (ZSTR_VAL(res) - ZSTR_VAL(s));
while (c < e) {
*r = toupper(*c);
r++;
c++;
}
*r = '[=10=]';
return res;
}
c++;
}
return zend_string_copy(s);
}
PHP_FUNCTION(strtoupper)
{
zend_string *arg; <-- strtolower uses zend_string *str;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(arg) <-- strtolower uses Z_PARAM_STR(str)
ZEND_PARSE_PARAMETERS_END();
RETURN_STR(php_string_toupper(arg)); <-- strtolower uses RETURN_STR(php_string_tolower(str));
}
对于 strtolower
PHPAPI char *php_strtolower(char *s, size_t len)
{
unsigned char *c, *e;
c = (unsigned char *)s;
e = c+len; <-- strtoupper uses e = (unsigned char *)c+len;
while (c < e) {
*c = tolower(*c);
c++;
}
return s;
}
PHPAPI zend_string *php_string_tolower(zend_string *s)
{
unsigned char *c, *e;
c = (unsigned char *)ZSTR_VAL(s);
e = c + ZSTR_LEN(s);
while (c < e) {
if (isupper(*c)) {
register unsigned char *r;
zend_string *res = zend_string_alloc(ZSTR_LEN(s), 0);
if (c != (unsigned char*)ZSTR_VAL(s)) {
memcpy(ZSTR_VAL(res), ZSTR_VAL(s), c - (unsigned char*)ZSTR_VAL(s));
}
r = c + (ZSTR_VAL(res) - ZSTR_VAL(s));
while (c < e) {
*r = tolower(*c);
r++;
c++;
}
*r = '[=11=]';
return res;
}
c++;
}
return zend_string_copy(s);
}
PHP_FUNCTION(strtolower)
{
zend_string *str; <-- strtoupper uses zend_string *arg;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(str) <-- strtoupper uses Z_PARAM_STR(arg)
ZEND_PARSE_PARAMETERS_END();
RETURN_STR(php_string_tolower(str)); <-- strtoupper uses RETURN_STR(php_string_tolower(arg));
}
这些微小差异是否足以影响那几纳秒的性能,我不知道....不确定为什么会有差异