ホームページ  >  記事  >  php教程  >  PHP関数の部分文字列置換str

PHP関数の部分文字列置換str

WBOY
WBOYオリジナル
2016-06-21 08:55:061044ブラウズ

str_replace 部分文字列置換 [str_replace]
混合 str_replace ( 混合 $search 混合 $replace 混合 $subject [, int &$count ] )
php functionstr_replace: 文字列または配列を返します。文字列または配列は、すべての search の検索であり、すべて に置き換えられます。 これで、この関数の使用法をいくつか知ることができます。たとえば、str_replace("#", "-", "dizaz#7#final")、str_replace(array('#', '$'), " - "、"dizaz#7$final") など、これらの呼び出しメソッドは PHP 内でどのように実装されているのでしょうか? [PHP カーネルを深く理解する] という観点から、ここで簡単な分析を行います。 テストコード: コードをコピー

コードは次のとおりです:


$object = "dizaz #7#final"; $res = str_replace("#", "-", $object);

上記と同様の文字で始まる場合は、先頭の「#」が文字「-」に置き換えられます。


準備作業:

PHP ソース コードをダウンロードします。http://www.php.net からダウンロードします。
独自のコード読み取りツールを作成します [VIM+CSCOPE を使用します] : Linux ユーザーには、グラフィカル ソース コード表示ツール kscope [google]
コンパイル ツール [gcc]、デバッグ ツール [gdb] もお勧めします。また、GDB グラフィカル ポート DDD も非常に優れており、PHP ソース コードをコンパイルするには

を推奨します。 --enable-debug を忘れずに使用してください [もちろん、./configure --help を使用して、PHP が提供するコンパイル オプションの一部を確認することもできます。多くのことが得られます]
分析を開始します:

「PHP カーネルの徹底理解」を読むと、PHP が提供する標準関数が格納されているディレクトリが PHP-SOURCE-DIR/ext/standard ディレクトリにあることがわかります。これは文字列関数です。このディレクトリで str_replace 関数によって実装されたファイル文字列を見つけるのは簡単です。次のステップは、このファイルを分析することです。 [もちろん CScope でロックするのは簡単です。cs find s str_replace を使用します。]

クエリを実行してその定義と実装を確認します:



コードをコピー

コードは次のとおりです:


/* {{{ protomixed str_replace(mixed search,mixed replace,mixed subject [, int &replace_count])
haystack 内のすべての検索を置換します。 replace */

PHP_FUNCTION(str_replace) { php_str_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1) }

/* }}} */


次に、関数 php_str_replace_common 関数を表示する必要があります



コードをコピー

コードは次のとおりです:


/* {{{ php_str_replace_common
*/
static void php_str_replace_common(INTERNAL_FUNCTION_PARAMETERS, int case_sensitivity)
{
/**
* TODO
* typedef struct _zval_struct zval;
* typedef struct _zend_class_entry zend_class_entry
*
* struct _zval_struct {
* zvalue_value 値;
* zend_uint refcount__gc;
* zend_uchar 型;
* zend_uchar is_ref__gc;
* };
*
* typedef Union _zvalue_value {
* long lval;
* ダブル dval;
* struct {
* char *val;
* int len;
* } str;
* ハッシュテーブル *ht;
* zend_object_value obj;
* } zvalue_value;
*
* typedef struct _zend_object {
* zend_class_entry *ce;
* ハッシュテーブル *プロパティ;
* ハッシュテーブル *ガード;
* } zend_object;
*
*/
zval **件名、**検索、**置換、**件名エントリ、**zcount = NULL;
zval *結果;
char *string_key;
uint string_key_len;
ulong num_key;
int カウント = 0;
int argc = ZEND_NUM_ARGS();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZZ", &search, &replace, &subject, &zcount) == FAILURE) {
return;
}
SEPARATE_ZVAL(検索);
SEPARATE_ZVAL(置換);
SEPARATE_ZVAL(件名);
/* 文字列を扱っていることを確認し、置換を実行します。 */
if (Z_TYPE_PP(search) != IS_ARRAY) {
....//代码省滤
} else { /* サブジェクトが配列でない場合 */
php_str_replace_in_subject(*検索、*置換、件名、戻り値、大文字と小文字の区別、(argc > 3) &count : NULL);
}
if (argc > 3) {
zval_dtor(*zcount);
ZVAL_LONG(*zcount, count);
}
}
/* }}} */


继续跟追跡php_str_replace_in_subject

复制代代码如下:


/* {{{ php_str_replace_in_subject
*/
static void php_str_replace_in_subject(zval *search, zval *replace, zval **subject, zval *result, int case_sensitivity, int *replace_count)
{
zval **search_entry,
**replace_entry = NULL,
temp_result;
char *replace_value = NULL;
int replace_len = 0;
/* 文字列を扱っていることを確認してください。 */
convert_to_string_ex(件名);
Z_TYPE_P(結果) = IS_STRING;
if (Z_STRLEN_PP(件名) == 0) {
ZVAL_STRINGL(result, "", 0, 1);
戻る;
}
/* 検索が配列の場合 */
if (Z_TYPE_P(search) == IS_ARRAY) {
...//不走这步
} else {
if (Z_STRLEN_P(search) == 1) { // 例中にのみ”#”があるため、この操作を実行します。
php_char_to_str_ex(Z_STRVAL_PP(subject),//subject の値、また dizaz#7#final
Z_STRLEN_PP(subject), //subject の長さを取得します
Z_STRVAL_P(search)[0], //ただ 1 つある”#” ため、最初の 1 文字だけが必要です
Z_STRVAL_P(replace), / /代替希望の文字符,现在是“-”
Z_STRLEN_P(replace), //目标文字の長さ,现在である1
result, //代替换结結果
case_sensitivity, //大小写しが敏感かどうか,默认是1
replace_count); //置換次数
} else if (Z_STRLEN_P(search) > 1) {
Z_STRVAL_P(result) = php_str_to_str_ex(Z_STRVAL_PP(件名), Z_STRLEN_PP(件名),
Z_STRVAL_P(検索), Z_STRLEN_P( search)、
Z_STRVAL_P(置換)、Z_STRLEN_P(置換)、&Z_STRLEN_P(結果)、case_sensitivity、replace_count);
} else {
MAKE_COPY_ZVAL(件名, 結果);
}
}
}


に到達したため、私たちの目標は php_char_to_str_ex 関数を最終的に決定しました。この関数の数を分析する必要があるだけで OK です。その結果は次のとおりです。

复制代码代码如下:


/* {{{ php_char_to_str_ex
*/
PHPAPI int php_char_to_str_ex(char *str, uint len, char from, char *to, int to_len, zval *result, int case_sensitivity, int * replace_count)
{
int char_count = 0;
char *source、*target、*tmp、*source_end=str+len、*tmp_end = NULL; if (case_sensitivity) { //今度は case_sensitivity = 1
char *p = str, *e = p + len;
//何回置換する必要があるかを計算します
while ((p = memchr (p, from , (e - p))) {
char_count++;
}
} else {
for (source = str;source if (to lower(*source) == to lower(from)) {
char_count++;
}
}
}
if (char_count == 0 && case_sensitivity) {
ZVAL_STRINGL( result, str, len, 1);
return 0;
}
//置換後の長さを計算し、結果に格納します。
Z_STRLEN_P(result) = len + (char_count * (to_len - 1));
//メモリを適用し、置換されたデータを保存します
Z_STRVAL_P(result) = target =safe_emalloc(char_count, to_len, len + 1);
//設定結果は文字列です
Z_TYPE_P(result) = IS_STRING;
//ターゲットと結果の値は同じメモリブロックを指すため、ターゲットのみ
は、 (case_sensitivity) {
char *p = str, *e = p + len, *s = str
while ((p = memchr(p, (e - p)))) { / /どの文字を決定します #
memcpy(target, s, (p - s)) // # より前のデータをターゲット
target += p - s; >memcpy( target, to, to_len); // ターゲット文字を target にコピーします [もちろん、このときのターゲットは target+p-s から始まります]
target += to_len;
s = p; ;
if (replace_count) {
*replace_count += 1; // 置換の数を設定します
}
}
// 後でさらに追加するターゲットがメモリ ブロックは既にデータを置き換えていることを指します。
if (s < e) {
memcpy(target, s, (e - s));
target += e - s;
} for (source = str;source if (to lower(*source) == to lower(from)) {
replaced = 1;
if (replace_count) {
*replace_count += 1;
}
for (tmp = to, tmp_end = tmp+to_len; tmp < tmp_end; tmp++) {
*target = *tmp;

} else {
*target = *source;
}
}
}
return
}
/* }}} */


上でコメントしたように、これで文字の文字列への置換が完了します。戻り方や詳しい処理については、PHPの実行処理を相対的に理解している必要があります。
もちろん、gdb を使用して php_char_to_str_ex 関数にブレークポイントを設定し、その詳細な実行プロセスを理解することもできます。
次の記事は文字列を文字列に置き換える解析についてです。
概要:
結果は zval に保存されます。
置換の実装は非常に巧妙であり、学ぶことができます。
引き続きソース コードを表示し、さらに執筆スキルと設計スキルを学ぶ必要があります。





声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。