我可以使用explode
执行此操作(或与strrpos
一起使用),但我更喜欢使用preg_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!!!
答案 0 :(得分:3)
你很亲密,你正在寻找的模式是:
([^_]*)$
这将仅匹配不是下划线的文本,尽可能接近字符串的末尾。它也不包括下划线,因为您的替换字符串不使用$1
来指定匹配的组。
答案 1 :(得分:2)
根据您的常用搜索字符串和您的PCRE版本,preg_replace
或strrpos
可能最佳:
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
提供资金,直到最后一个下方有大量下划线。< / p>
编辑:我将bfrohs's regex插入套件中,除非要替换的下划线靠近字符串的开头,否则效果不佳:
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
答案 2 :(得分:1)
问题是第一个下划线是匹配的。您需要在下划线之外的任何内容下划线:
'/_([^_]*)$/'
答案 3 :(得分:1)
常规表达式/_(.*)$/
匹配下划线,后跟任何文本,后跟字符串的结尾。没有任何东西可以保留包含下划线的“任何文本”,默认情况下,匹配器将选择最左边,最长的匹配。所以在'a_b_c'中它恰好在'a'之后匹配。
您可以通过将.
(匹配任何字符)替换为字符类[^_]
来修复此问题,该字符类匹配除下划线之外的任何字符。
此外,由于您没有对捕获的组执行任何操作,因此不需要括号。因为,根据您的示例,您不想替换下划线本身,您应该将它从正则表达式中删除。
function bar($string, $replacement)
{
return preg_replace('/[^_]*$/', $replacement, $string, 1);
}
答案 4 :(得分:1)
如果考虑速度,使用strpos将比preg_replace更快。所有字符串函数(据我所知)比正则表达式函数慢。
答案 5 :(得分:0)
'/([^_]+)$/'
匹配所有但下划线 最后一个下划线。
注意:没有必要将下划线与此匹配。这样,当您进行替换时,您不会丢失最后一个下划线。
答案 6 :(得分:0)
这看起来像一个表情符号,但我认为它应该有效:
return preg_replace('/(.*_).*/', $replacement, $string);