php natsort内核函数浅析
前端之家收集整理的这篇文章主要介绍了
php natsort内核函数浅析,
前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
@H_403_0@官方手册(<A href="http://us.php.net/manual/en/function.natsort.php">http://us.php.net/manual/en/function.natsort.php)
<div class="codetitle"><a style="CURSOR: pointer" data="51977" class="copybut" id="copybut51977" onclick="doCopy('code51977')"> 代码如下:
<div class="codebody" id="code51977">
bool natsort ( array &$array )
This function implements a sort algorithm that orders alphanumeric strings in the way a human being would while maintaining key/value associations. This is described as a "natural ordering". An example of the difference between this algorithm and the regular computer string sorting algorithms (used in sort()) can be seen in the example below.
据官方手册还可以得到这样的结果: img1.png img2.png img10.png img12.png 显然这很适合对类似
文件名的排序。从结果看这种自然算法应该是去掉头和尾的非数字部分,然后对留下来的数字部分进行排序,究竟是不是,还是看一下
PHP源码吧。
<div class="codetitle">
<a style="CURSOR: pointer" data="43691" class="copybut" id="copybut43691" onclick="doCopy('code43691')"> 代码如下: <div class="codebody" id="code43691">
//从ext/standard/array.c抽取的相关
代码如下
static int
PHP_array_natural_general_compare(const void
a,const void b,int fold_case) /
{{{ /
{
Bucket
f,s;
zval
fval,sval;
zval first,second;
int result;
f = *((Bucket
) a);
s = *((Bucket *) b);
fval = ((zval ) f->pData);
sval = *((zval
) s->pData);
first = fval;
second = sval;
if (Z_TYPE_P(fval) != IS_STRING) {
zval_copy_ctor(&first);
convert_to_string(&first);
}
if (Z_TYPE_P(sval) != IS_STRING) {
zval_copy_ctor(&second);
convert_to_string(&second);
}
result = strnatcmp_ex(Z_STRVAL(first),Z_STRLEN(first),Z_STRVAL(second),Z_STRLEN(second),fold_case);
if (Z_TYPE_P(fval) != IS_STRING) {
zval_dtor(&first);
}
if (Z_TYPE_P(sval) != IS_STRING) {
zval_dtor(&second);
}
return result;
}
/ }}} /
static int PHP_array_natural_compare(const void a,const void b TSRMLS_DC) / {{{ /
{
return PHP_array_natural_general_compare(a,b,0);
}
/ }}} /
static void PHP_natsort(INTERNAL_FUNCTION_PARAMETERS,int fold_case) / {{{ /
{
zval array;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"a",&array) == FAILURE) {
return;
}
if (fold_case) {
if (zend_hash_sort(Z_ARRVAL_P(array),zend_qsort,PHP_array_natural_case_compare,0 TSRMLS_CC) == FAILURE) {
return;
}
} else {
if (zend_hash_sort(Z_ARRVAL_P(array),PHP_array_natural_compare,0 TSRMLS_CC) == FAILURE) {
return;
}
}
RETURN_TRUE;
}
/ }}} /
/ {{{ proto void natsort(array &array_arg)
Sort an array using natural sort /
PHP_FUNCTION(natsort)
{
PHP_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
}
/ }}} /
虽然是第一次查看
PHP的内核
代码,不过凭借多年看
代码的经验,还是很容易找到这个自然排序算法的核心就是
函数:strnatcmp_ex(位于ext/standard/strnatcmp.c
文件中)。 <div class="codetitle">
<a style="CURSOR: pointer" data="21664" class="copybut" id="copybut21664" onclick="doCopy('code21664')"> 代码如下: <div class="codebody" id="code21664">
/ {{{ compare_right
*/
static int
compare_right(char const *
a,char const aend,char const b,char const
bend)
{
int bias = 0;
/ The longest run of digits wins. That aside,the greatest
value wins,but we can't know that it will until we've scanned
both numbers to know that they have the same magnitude,so we
remember it in BIAS.
/
for(;; (a)++,(
b)++) {
if ((a == aend || !isdigit((int)(unsigned char)
a)) &&
(*b == bend || !isdigit((int)(unsigned char)*b)))
return bias;
else if (a == aend || !isdigit((int)(unsigned char)a))
return -1;
else if (*b == bend || !isdigit((int)(unsigned char)
b))
return +1;
else if (a <
b) {
if (!bias)
bias = -1;
} else if (a >
b) {
if (!bias)
bias = +1;
}
}
return 0;
}
/ }}} /
/ {{{ compare_left
/
static int
compare_left(char const a,char const
bend)
{
/ Compare two left-aligned numbers: the first to have a
different value wins.
/
for(;; (a)++,(
b)++) {
if ((a == aend || !isdigit((int)(unsigned char)
a)) &&
(*b == bend || !isdigit((int)(unsigned char)*b)))
return 0;
else if (a == aend || !isdigit((int)(unsigned char)a))
return -1;
else if (*b == bend || !isdigit((int)(unsigned char)
b))
return +1;
else if (a <
b)
return -1;
else if (a > *
b)
return +1;
} return 0;
}
/ }}}
/
/ {{{ strnatcmp_ex
call in array.c: strnatcmp_ex(Z_STRVAL(first),fold_case);
/
PHPAPI int strnatcmp_ex(char const
a,size_t a_len,char const b,size_t b_len,int fold_case)
{
char ca,cb;
char const
ap,bp;
char const
aend = a + a_len,
bend = b + b_len;
int fractional,result;
if (a_len == 0 || b_len == 0)
return a_len - b_len;
ap = a;
bp = b;
while (1) {
ca =
ap; cb = bp;
/
skip over leading spaces or zeros /
while (isspace((int)(unsigned char)ca) || (ca == '0' && (ap+1 < aend) && (
(ap+1)!='.')))
ca = ++ap;
while (isspace((int)(unsigned char)cb) || (cb == '0' && (bp+1 < bend) && (
(bp+1)!='.')))
cb = ++bp;
/
process run of digits /
if (isdigit((int)(unsigned char)ca) && isdigit((int)(unsigned char)cb)) {
fractional = (ca == '0' || cb == '0');
if (fractional)
result = compare_left(&ap,aend,&bp,bend);
else
result = compare_right(&ap,bend);
if (result != 0)
return result;
else if (ap == aend && bp == bend)
/
End of the strings. Let caller sort them out. /
return 0;
else {
/
Keep on comparing from the current point. /
ca =
ap; cb = bp;
}
}
if (fold_case) {
ca = toupper((int)(unsigned char)ca);
cb = toupper((int)(unsigned char)cb);
}
if (ca < cb)
return -1;
else if (ca > cb)
return +1;
++ap; ++bp;
if (ap >= aend && bp >= bend)
/
The strings compare the same. Perhaps the caller
will want to call strcmp to break the tie. /
return 0;
else if (ap >= aend)
return -1;
else if (bp >= bend)
return 1;
}
}
/
}}} /