Alex
Alex

Reputation: 68396

Remove a string from the beginning of a string

I have a string that looks like this:

$str = "bla_string_bla_bla_bla";

How can I remove the first bla_; but only if it's found at the beginning of the string?

With str_replace(), it removes all bla_'s.

Upvotes: 203

Views: 206517

Answers (11)

mickmackusa
mickmackusa

Reputation: 47764

I generally don't have an appetite for techniques that need 3 function calls or generate and array to produce a string when a single regex function will do.

I want to mention that if you use pattern delimiters that are covered in the default mask of preg_quote(), then you won't need to nominate the second parameter (# is one of those characters).

Documenation: https://www.php.net/manual/en/function.preg-quote.php

The special regular expression characters are: . \ + * ? [ ^ ] $ ( ) { } = ! < > | : - #

Note that / is not a special regular expression character.

Code: (Demo)

$str = preg_replace('#^' . preg_quote($prefix) . '#'), '', $str);

For completeness, I want to add to this page that sscanf() can be a suitable technique so long as you are in "control" of the prefix string and can confidently assign all characters after the prefix to a placeholder. In the asker's sample input, there are no spaces in the input string, so %s will suffice. If there are any spaces in the substring after the prefix, then %s is no good -- you might use a negated expression with a character that will not occur like %[^~] or similar. This technique will modify the input string by reference if needed. (Demo)

sscanf($str, "$prefix%s", $str);

I'll admit that sscanf() isn't the most intuitive tool for this task and there are scenarios where it is unsuitable, but for the presented task the single function call works as desired. For cases when you have a prefix followed by a number, sscanf() with %d in the format parameter will auto-cast the matched string as an integer. So there may be some scenarios where it is more ideal than a preg_ function call.

Upvotes: 0

Tac Tacelosky
Tac Tacelosky

Reputation: 3426

Symfony users can install the string component and use trimPrefix()

u('file-image-0001.png')->trimPrefix('file-');           // 'image-0001.png'

Upvotes: 1

Dan Gurin
Dan Gurin

Reputation: 341

In PHP 8+ we can simplify using the str_starts_with() function:

$str = "bla_string_bla_bla_bla";
$prefix = "bla_";
if (str_starts_with($str, $prefix)) {
  $str = substr($str, strlen($prefix));
}

https://www.php.net/manual/en/function.str-starts-with.php

EDIT: Fixed a typo (closing bracket) in the example code.

Upvotes: 21

Giacomo1968
Giacomo1968

Reputation: 26056

Lots of different answers here. All seemingly based on string analysis. Here is my take on this using PHP explode to break up the string into an array of exactly two values and cleanly returning only the second value:

$str = "bla_string_bla_bla_bla";
$str_parts = explode('bla_', $str, 2);
$str_parts = array_filter($str_parts);
$final = array_shift($str_parts);
echo $final;

Output will be:

string_bla_bla_bla

Upvotes: 1

Stefan Gabos
Stefan Gabos

Reputation: 1471

Here's an even faster approach:

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

Upvotes: 8

Aleksandar Bosakov
Aleksandar Bosakov

Reputation: 21

Nice speed, but this is hard-coded to depend on the needle ending with _. Is there a general version? – toddmo Jun 29 at 23:26

A general version:

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

Some 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);

On my quite old home PC:

$ php bench.php

Outputs:

   strpos+strlen : 0.158388 s
         explode : 0.126772 s

Upvotes: 1

Pavel
Pavel

Reputation: 389

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

Upvotes: 28

Fabio Mora
Fabio Mora

Reputation: 5479

Plain form, without regex:

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

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

Takes: 0.0369 ms (0.000,036,954 seconds)

And with:

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

Takes: 0.1749 ms (0.000,174,999 seconds) the 1st run (compiling), and 0.0510 ms (0.000,051,021 seconds) after.

Profiled on my server, obviously.

Upvotes: 411

Inca
Inca

Reputation: 1901

I think substr_replace does what you want, where you can limit your replace to part of your string: https://www.php.net/manual/en/function.substr-replace.php (This will enable you to only look at the beginning of the string.)

You could use the count parameter of str_replace ( https://www.php.net/manual/en/function.str-replace.php ), this will allow you to limit the number of replacements, starting from the left, but it will not enforce it to be at the beginning.

Upvotes: -1

cbrandolino
cbrandolino

Reputation: 5883

Here.

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

Upvotes: 6

Tatu Ulmanen
Tatu Ulmanen

Reputation: 124758

You can use regular expressions with the caret symbol (^) which anchors the match to the beginning of the string:

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

Upvotes: 88

Related Questions