Remover uma sequência do início de uma sequência


Respostas:


339

Forma simples, sem regex:

$prefix = 'bla_';
$str = 'bla_string_bla_bla_bla';

if (substr($str, 0, strlen($prefix)) == $prefix) {
    $str = substr($str, strlen($prefix));
} 

Leva: 0,0369 ms (0,000,036,954 segundos)

E com:

$prefix = 'bla_';
$str = 'bla_string_bla_bla_bla';
$str = preg_replace('/^' . preg_quote($prefix, '/') . '/', '', $str);

Leva: 0,1749 ms (0,000,174,999 segundos) na 1ª execução (compilando) e 0,0510 ms (0,000,051,021 segundos) depois.

Perfilado no meu servidor, obviamente.


8
Eu nunca vi o operador ternário sofrer tanto abuso, um simples if(condition) { statement }teria sido muito mais claro.
Tatu Ulmanen

4
@ salathe: Eu aceito as críticas. Era uma curiosidade pessoal ver o que era mais rápido.
Fabio Mora

51
@ salathe, eu não entendo. Foram propostas soluções idiomáticas e baseadas em regex: comparar as duas em termos de eficiência ajuda a encontrar a melhor resposta (novamente em termos de eficiência). Por que isso é mau?
Cbrandolino

5
@cbrandolino, ninguém disse que era mau . Eu apenas pensei que era totalmente irrelevante para a pergunta; muito parecido com "aqui estão duas soluções, e aqui está uma foto de alguns gatinhos para mais votos" seria.
Salathe

5
if (substr($str, 0, strlen($prefix)) == $prefix) pode ser alterado para if (0 === strpos($str, $prefix))evitar a alocação de memória desnecessária, mantendo a mesma legibilidade :)
xDaizu

63

Você pode usar expressões regulares com o símbolo de sinal de intercalação ( ^) que ancora a correspondência no início da sequência:

$str = preg_replace('/^bla_/', '', $str);

Gostaria de saber se funciona mais rápido que a substr()versão ... Acho que funciona, e deve ser marcado como resposta adequada.
Flash Thunder

exceto que deve ser preg_quote'd
vp_arth

Eu acho que isso é muito menos doloroso para os olhos de um programador e mais intuitivo. Mesmo se perder no desempenho para outra solução sugerida (da qual realmente duvido), ainda assim prefiro isso.
Fr0zenFyr

multibytepesadelo é outro problema com outras soluções, enquanto isso funciona bem se a codificação do arquivo estiver correta. De qualquer forma, não deveria estar no escopo desta pergunta, para que eu não me importasse.
Fr0zenFyr

Voltamos a mencionar que isso tem um benefício adicional de trabalhar com uma variedade de sequências de assuntos. substre strposnão pode aceitar uma matriz. Lá está, um ganho de desempenho definitivo se você estiver lidando com uma matriz. Felicidades!
Fr0zenFyr

20
function remove_prefix($text, $prefix) {
    if(0 === strpos($text, $prefix))
        $text = substr($text, strlen($prefix)).'';
    return $text;
}

10
O .''não é necessário.
NateS 11/11

1
Pelo que vale a pena, já que todo mundo parece estar otimizando aqui, este é consistentemente mais rápido pela minha contagem. 1 milhão de iterações ficou em 0,17 segundos, enquanto que (substr($str, 0, strlen($prefix)) == $prefix)a partir da resposta aceita foi mais como 0,37
billynoah

5

Aqui.

$array = explode("_", $string);
if($array[0] == "bla") array_shift($array);
$string = implode("_", $array);

2
Meça 0.0000459153 segundos :)
Fabio Mora

Boa velocidade, mas isso é codificado para depender da agulha que termina com _. Existe uma versão geral?
toddmo

0

Eu acho que substr_replace faz o que você quer, onde você pode limitar sua substituição a parte da sua string: http://nl3.php.net/manual/en/function.substr-replace.php (Isso permitirá que você veja apenas o início da string.)

Você pode usar o parâmetro count de str_replace ( http://nl3.php.net/manual/en/function.str-replace.php ), isso permitirá que você limite o número de substituições, começando pela esquerda, mas não fará com que seja no início.


1
substr_replacesubstituirá os caracteres no intervalo especificado, independentemente de serem o prefixo que você deseja remover ou outra coisa. O OP quer remover bla_"apenas se for encontrado no início da string".
Olivier 'Ölbaum' Scherler 31/03

0

Velocidade agradável, mas isso é codificado para depender da agulha que termina com _. Existe uma versão geral? - toddmo 29/06 às 23:26

Uma versão geral:

$parts = explode($start, $full, 2);
if ($parts[0] === '') {
    $end = $parts[1];
} else {
    $fail = true;
}

Alguns benchmarks:

<?php

$iters = 100000;
$start = "/aaaaaaa/bbbbbbbbbb";
$full = "/aaaaaaa/bbbbbbbbbb/cccccccccc/dddddddddd/eeeeeeeeee";
$end = '';

$fail = false;

$t0 = microtime(true);
for ($i = 0; $i < $iters; $i++) {
    if (strpos($full, $start) === 0) {
        $end = substr($full, strlen($start));
    } else {
        $fail = true;
    }
}
$t = microtime(true) - $t0;
printf("%16s : %f s\n", "strpos+strlen", $t);

$t0 = microtime(true);
for ($i = 0; $i < $iters; $i++) {
    $parts = explode($start, $full, 2);
    if ($parts[0] === '') {
        $end = $parts[1];
    } else {
        $fail = true;
    }
}
$t = microtime(true) - $t0;
printf("%16s : %f s\n", "explode", $t);

No meu PC doméstico bastante antigo:

$ php bench.php

Saídas:

   strpos+strlen : 0.158388 s
         explode : 0.126772 s

0

Aqui está uma abordagem ainda mais rápida:

// strpos is faster than an unnecessary substr() and is built just for that 
if (strpos($str, $prefix) === 0) $str = substr($str, strlen($prefix));

0

Isso removerá a primeira correspondência onde quer que seja encontrada, isto é, início ou meio ou fim.

$str = substr($str, 0, strpos($str, $prefix)).substr($str, strpos($str, $prefix)+strlen($prefix));


-6

str_replace ( mixed $search , mixed $replace , mixed $subject [, int &$count ] )

agora faz o que você quer.

$str = "bla_string_bla_bla_bla";
str_replace("bla_","",$str,1);

7
A str_replace()da função $countparâmetro deverá ser uma variável passada por referência para conter o número de substituições encontrado, não limitar o número de substituições.
AL o X

-6

Retire www. desde o início da string, esta é a maneira mais fácil (ltrim)

$a="www.google.com";
echo ltrim($a, "www.");

8
O segundo parâmetro é um mapa de caracteres a serem removidos do lado esquerdo da string ( php.net/manual/function.ltrim.php ). Portanto: ltrim($a, "w.");faria o trabalho apenas se o domínio não iniciar com um "w". ltrim ('m.google.com', ".omg")resulta em le.com.
Fragmentedreality

mas resolve o problema específico da questão, +1
chulian 05/04

1
ele realmente resolve o problema específico que ele fez para sua resposta - não o problema da pergunta. mesmo se você escolher ltrim, ele será usado incorretamente. o segundo parâmetro é uma lista de caracteres que devem ser aparados; portanto, um único "w."seria suficiente.
Fragmentedreality

Eu acho que, IMHO, é correto para perguntas e problemas.
abkrim

2
Após o teste com vários testes mudar minha opinião .... não trabalho para a pergunta sobre quaisquer situações
abkrim
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.