3

を使用してこれを行うことができます (または を使用してexplode楽しんでください)。さらに、簡潔でエレガントです。strrpospreg_replace

目的は、渡された文字列に置き換えられた最後の文字に続くa_b_c別の文字列を取得するような文字列を指定することです。_

正規表現が苦手です。私は勉強中に良い本を買う時間を見つけなければなりません。とにかく、この正規表現を文字列の末尾に一致させ、最後のアンダースコアに続く任意の文字をキャプチャしてみ'/_(.*)$/'まし

私の議論のどこが間違っているのでしょうか?

// Do it using explode
function foo($string, $replacement)
{
    $pieces = explode('_', $string);
    array_pop($pieces);
    return implode('_', array_merge($pieces, array($replacement)));
}

// Do it using regular expression (not working)
function bar($string, $replacement)
{
    return preg_replace('/_(.*)$/', $replacement, $string);
}

echo foo('a_b_c', 3); // Prints a_b_3
echo bar('a_b_c', 3); // Prints a3 wrong!!!
4

7 に答える 7

3

あなたは近かった、あなたが探しているパターンはこれです:

([^_]*)$

これは、文字列の末尾からできるだけ近い、アンダースコアではないテキストのみに一致します。$1置換文字列は一致するグループを指定するために使用されないため、アンダースコアも含まれません。

于 2012-04-19T20:16:34.433 に答える
2

一般的な検索文字列と PCRE のバージョンに応じて、 または のいずれpreg_replacestrrposがおそらく最適です。

機能

function usingExplode($string, $replacement) {
    $pieces = explode('_', $string);
    array_pop($pieces);
    return implode('_', array_merge($pieces, array($replacement)));
}

function usingStrrpos($string, $replacement) {
    return substr($string, 0, strrpos($string, '_') + 1) . $replacement;
}

function usingPreg($string, $replacement) {
    return preg_replace('/_[^_]*$/', '_' . $replacement, $string);
}

テストハーネス

function speedTest($function, $string, $count = 100000) {
    $start = microtime(true);

    for ($i = 0; $i < $count; $i++) {
        $function($string, 'replacement');
    }

    $end = microtime(true);

    printf('%-12s: %01.2fs%s', $function, $end - $start, PHP_EOL);
}

$tests = array('a_b_c', 'abcdefghijklmnopqrstuvwxy_z', 'a_bcdefghijklmnopqrstuvwxyz', 'a_b_c_d_e_f_g_h_i_j_k_l_m_n_o_p_q_r_s_t_u_v_w_x_y_z');

foreach ($tests as $test) {
    echo $test . ':' . PHP_EOL;
    speedTest('usingExplode', $test);
    speedTest('usingStrrpos', $test);
    speedTest('usingPreg',    $test);
    echo PHP_EOL;
}

結果

a_b_c:
usingExplode: 0.64s
usingStrrpos: 0.34s
usingPreg   : 0.33s

abcdefghijklmnopqrstuvwxy_z:
usingExplode: 0.61s
usingStrrpos: 0.32s
usingPreg   : 0.32s

a_bcdefghijklmnopqrstuvwxyz:
usingExplode: 0.60s
usingStrrpos: 0.32s
usingPreg   : 0.32s

a_b_c_d_e_f_g_h_i_j_k_l_m_n_o_p_q_r_s_t_u_v_w_x_y_z:
usingExplode: 1.39s
usingStrrpos: 0.32s
usingPreg   : 0.71s

(少なくとも PHP 5.4.0 を使用した私のセットアップでpreg_replaceは)、strrpos最後のアンダースコアの前に多数のアンダースコアが表示されるまで、そのお金のために実行されることに注意してください。

編集: bfrohs の正規表現をスイートにプラグインしましたが、置換するアンダースコアが文字列の先頭近くにない限り、うまく機能しません:

a_b_c:
usingPreg2: 0.40s

abcdefghijklmnopqrstuvwxy_z:
usingPreg2: 1.91s

a_bcdefghijklmnopqrstuvwxyz:
usingPreg2: 0.38s

a_b_c_d_e_f_g_h_i_j_k_l_m_n_o_p_q_r_s_t_u_v_w_x_y_z:
usingPreg2: 1.04s
于 2012-04-19T20:53:17.703 に答える
1

速度が重要な場合は、strpos を使用すると preg_replace よりも高速になります。すべての文字列関数は (私の知る限り) 正規表現関数よりも遅いです。

速度テストの 1 つを次に示します: http://lzone.de/articles/php-string-search.htm

于 2012-04-19T20:22:42.807 に答える
1

問題は、最初のアンダースコアが一致することです。アンダースコア以外のアンダースコアの後に何かが必要です:

'/_([^_]*)$/'
于 2012-04-19T20:17:07.860 に答える
1

正規表現/_(.*)$/は、アンダースコアの後に任意のテキストが続き、その後に文字列の末尾が続くものと一致します。その「任意のテキスト」にアンダースコアが含まれないようにするものは何もありません。デフォルトでは、マッチャーは最も左にある最長の一致を選択します。したがって、「a_b_c」では、「a」の直後に一致します。

(任意の文字に一致する) をアンダースコア以外の任意の文字に一致する.文字クラスに置き換えることで、これを修正できます。[^_]

また、キャプチャされたグループに対して何もしていないため、括弧は必要ありません。また、例に基づいて、アンダースコア自体を置き換えたくないため、正規表現から除外する必要があります。

function bar($string, $replacement)
{
    return preg_replace('/[^_]*$/', $replacement, $string, 1);
}
于 2012-04-19T20:17:53.240 に答える
0

'/([^_]+)$/'最後のアンダースコアののアンダースコア以外のすべて一致します。

注:アンダースコアをこれと一致させる必要はありません。そうすれば、置換を行うときに最後のアンダースコアが失われることはありません。

于 2012-04-19T20:16:21.440 に答える
0

これは絵文字のように見えますが、うまくいくと思います:

return preg_replace('/(.*_).*/', $replacement, $string);
于 2012-04-19T22:23:57.887 に答える