PHP如何替换多个字符串不一样位置不一样长度的子串

都知道substr_replace能够替换指定位置的子串。好比substr_repace("Hello Test",'xxxx',1,4)替换成Hxxxx Testphp

那么如何实现替换多个字符串不一样位置不一样长度的子串。数组

$data = [
'Hello Test',
'QQ mytest',
'Sina email'
]
复制代码

好比上面一个数组,如今须要把数组第i个元素的第i个字符串后面的4个字符串替换陈xxxxbash

$data = [
	'Hxxxx Test',
	'QQxxxxest',
	'Sinxxxxail'
]
复制代码

其实,substr_replace也能够实现多个字符串子串的替换。函数

substr_replace函数定义ui

substr_replace ( mixed $string , mixed $replacement , mixed $start [, mixed $length ] ) : mixed

复制代码

substr_replace源码在ext/standard/string.c中。先看一下总体的结构spa

...
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzz|z/", &str, &repl, &from, &len) == FAILURE) {
	return;
}
...
if (Z_TYPE_P(str) != IS_ARRAY) {
	if (Z_TYPE_P(from) != IS_ARRAY) {
		if (Z_TYPE_P(repl) == IS_ARRAY) {
			...
		} else {
			repl_str = Z_STR_P(repl);
		}
	} else {
		php_error_docref(NULL, E_WARNING, "Functionality of 'start' and 'length' as arrays is not implemented");
		RETURN_STR_COPY(Z_STR_P(str));
	}
} else { 
...
}
复制代码

substr_repace首先根据替换须要替换的内容的类型区分。字符类型和数组类型的替换采用不一样的处理方式。同时字符类型也对起始位置参数from作了限制,这中状况下,不接受数组类型做为起始位置。.net

对于字符数据的替换code

if (Z_TYPE_P(repl) == IS_ARRAY) {
	repl_idx = 0;
	while (repl_idx < Z_ARRVAL_P(repl)->nNumUsed) {
		tmp_repl = &Z_ARRVAL_P(repl)->arData[repl_idx].val;
		if (Z_TYPE_P(tmp_repl) != IS_UNDEF) {
			break;
		}
		repl_idx++;
	}
	if (repl_idx < Z_ARRVAL_P(repl)->nNumUsed) {
		repl_str = zval_get_string(tmp_repl);
		repl_release = 1;
	} else {
		repl_str = STR_EMPTY_ALLOC();
	}
} else {
	repl_str = Z_STR_P(repl);
}

result = zend_string_safe_alloc(1, Z_STRLEN_P(str) - l + ZSTR_LEN(repl_str), 0, 0);

memcpy(ZSTR_VAL(result), Z_STRVAL_P(str), f);
if (ZSTR_LEN(repl_str)) {
	memcpy((ZSTR_VAL(result) + f), ZSTR_VAL(repl_str), ZSTR_LEN(repl_str));
}
memcpy((ZSTR_VAL(result) + f + ZSTR_LEN(repl_str)), Z_STRVAL_P(str) + f + l, Z_STRLEN_P(str) - f - l);
ZSTR_VAL(result)[ZSTR_LEN(result)] = '\0';
if (repl_release) {
	zend_string_release(repl_str);
}
RETURN_NEW_STR(result);

复制代码

若是替换的目标是一个数组,则取数组第一个元素做为实际替换的内容。orm

l是传入的第四个参数处理以后的长度值(l取值0-原字符串长度)。而后执行三个copy操做,分别把from以前的原始字符串,替换后的字符串,from+l以后的字符串拷贝到结果字符串中取。因此说,这里的l指定的是原字符串有多少个字符被替换。字符串

若是要替换的内容是一个字符串数组的话,内部处理结构以下:

ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(str), num_index, str_index, tmp_str) {
	zend_string *orig_str = zval_get_string(tmp_str);
	if (Z_TYPE_P(from) == IS_ARRAY) {
		...
		if (from_idx < Z_ARRVAL_P(from)->nNumUsed) {
			...
			from_idx++;
			...
		}
		...
	} else {
		...
	}
	if (argc > 3 && Z_TYPE_P(len) == IS_ARRAY) {
		...
		if (len_idx < Z_ARRVAL_P(len)->nNumUsed) {
			...
			len_idx++;
			...
		}
		...
	} else if (argc > 3) {
		l = Z_LVAL_P(len);
	} else {
		l = ZSTR_LEN(orig_str);
	}
	...
	if (Z_TYPE_P(repl) == IS_ARRAY) {
		...
		if (repl_idx < Z_ARRVAL_P(repl)->nNumUsed) {
			zend_string *repl_str = zval_get_string(tmp_repl);
			result_len += ZSTR_LEN(repl_str);
			repl_idx++;
			...
		}
	} else {
		...
	}
	zend_string_release(orig_str);
} ZEND_HASH_FOREACH_END();

复制代码

执行一个for循环,拆分红对每一个数组元素的处理。在数组处理中,须要处理起始位置参数,长度参数是数组的状况。因此循环中对form,len,repl参数类型进行检查。若是是数组类型,则在每次替换以后下标进行加一操做。保证每次循环,获取到的是对应于该数组元素须要替换的内容,起始位置,和替换长度。

有如下几点须要了解:

  1. length长度是指替换长度,用repacement替换 string[start]...string[start+length],下面几个实例可以很好的说明其中的含义。

length长度小于替换字符串长度的时候,好比substr_replace('Hello Test','xxxx',2) 输出内容Hxxxxlo Test。length长度大于替换字符串长度,好比substr_replace('Hello Test','xxxx',6) 输出内容Hxxxxest,length大于原字符串长度的时候,好比substr_replace('Hello Test','xxxx',12) 输出内容Hxxxx

  • string为字符串的时候,replacement能够是数组,实际替换是去数组第一个元素

substr_replace('Hello Test',['xxxx'],4)实际上和substr_replace('Hello Test','xxxx',4)效果同样

  • 当须要替换的内容是数组的时候,replacement,from,length能够是数组,也能够部分是数组。php对于几个数组参数,若是不对应会进行相应的处理
$s1 = substr_replace(["Hello Test"], ["xxxx"],[1,2],[3,4]);
$s1=>[
	[0]=>'Hxxxxo Test'
]
复制代码

起始位置和长度比要替换的内容多,自动忽略。

$s2 = substr_replace(["Hello Test","qqqq"], ["xxxx"],[1],[3]);
$s1=>[
	[0]=>'Hxxxxo Test',
	[1]=>''
]
复制代码

原数组多,替换后数组少,则至关于替换成空字符串,即等价于一下内容:

$s2 = substr_replace(["Hello Test","qqqq"], ["xxxx",""],[1],[3]);
$s1=>[
	[0]=>'Hxxxxo Test',
	[1]=>''
]
复制代码
$s2 = substr_replace(["Hello Test","qqqq"], ["xxxx","ff"],[1],[3]);
$s1=>[
	[0]=>'Hxxxxo Test',
	[1]=>'ff'
]
复制代码

替换起始位置,长度数组不够,则认为起始位置是0,长度是整个字符串。即等价于:

$s2 = substr_replace(["Hello Test","qqqq"], ["xxxx","ff"],[1,0],[3,strlen("qqqq")]);
$s1=>[
	[0]=>'Hxxxxo Test',
	[1]=>'ff'
]
复制代码

若是部分参数不是数组,则对须要替换的数组都是有效的。

$s2 = substr_replace(["Hello Test","qqqqq"], "xx",[1,0],3);
$s1=>[
	[0]=>'Hxxo Test',
	[1]=>'xxqq'
]
复制代码

等价于

$s2 = substr_replace(["Hello Test","qqqqq"], ["xx","xx"],[1,0],[3,3]);
$s1=>[
	[0]=>'Hxxo Test',
	[1]=>'xxqq'
]
复制代码
相关文章
相关标签/搜索