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'
]
複製代碼
相關文章
相關標籤/搜索