Видаліть рядок із початку рядка


146

У мене є рядок, який виглядає приблизно так:

$str = "bla_string_bla_bla_bla";

Як я можу видалити перший bla_; але лише якщо він знайдений на початку рядка?

З str_replace(), він видаляє всі bla_ .


1
Ви можете виявити s($str)->replacePrefix('_bla')корисні, як це знайдено в цій самостійній бібліотеці .
каре

Відповіді:


339

Звичайна форма, без регулярного вираження:

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

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

Займає: 0,0369 мс (0,000,036,954 секунди)

І з:

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

Займає: 0,1749 мс (0,000,174,999 секунди) 1-го запуску (компіляція) та 0,0510 мс (0,000,051,021 секунди) після.

Профільно на моєму сервері, очевидно.


8
Я ніколи не бачив, щоб потрійний оператор зловживав так сильно, простий if(condition) { statement }був би набагато зрозумілішим.
Тату Ульманен

4
@salathe: Я приймаю критику. Було особистою цікавістю бачити, що найшвидше.
Фабіо Мора

51
@salathe, я не розумію. Були запропоновані як ідіоматичні, так і на основі регулярних виразів рішення: порівняння двох за рівнем ефективності допомагає знайти найкращу (знову ж таки з точки зору ефективності) відповідь. Чому це зло?
cbrandolino

5
@cbrandolino, ніхто не сказав, що це було зло . Я просто вважав це абсолютно неважливим для питання; так само, як "ось два рішення, і ось малюнок деяких кошенят для більшої кількості грошей".
салат

5
if (substr($str, 0, strlen($prefix)) == $prefix) можна змінити, if (0 === strpos($str, $prefix))щоб уникнути зайвого розподілу пам’яті, зберігаючи таку ж читабельність :)
xDaizu

63

Ви можете використовувати регулярні вирази із символом caret ( ^), який закріплює збіг до початку рядка:

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

Цікаво, чи працює вона швидше, ніж substr()версія ... Я думаю, що це робить, і має бути позначена як відповідна відповідь.
Flash Thunder

крім цього він повинен бути preg_quote'd
vp_arth

Я думаю, що це набагато менш боляче для очей програміста і більш інтуїтивно зрозуміле. Навіть якщо це втратить продуктивність щодо іншого запропонованого рішення (у якому я дуже сумніваюся), я все-таки віддаю перевагу цьому.
Fr0zenFyr

multibyteкошмар - це ще одна проблема з іншими рішеннями, хоча це працює добре, якщо кодування файлу є правильним. У всякому разі, це не повинно входити до цього питання, щоб я не хвилювався.
Fr0zenFyr

Повернувшись до згадки, що це має додаткову перевагу роботи з масивом предметних рядків. substrі strposне можу прийняти масив. Ось певне підвищення продуктивності, якщо ви маєте справу з масивом. Ура!
Fr0zenFyr

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

10
.''Не потрібно.
NateS

1
Для чого це варто, оскільки кожен, здається, мікрооптимізує тут, це мій підрахунок постійно. 1 мільйон ітерацій прийшов о .17 сек, тоді як (substr($str, 0, strlen($prefix)) == $prefix)з прийнятої відповіді було більше схоже на
.37

5

Ось

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

2
Відміряйте 0,0000459153 секунди :)
Фабіо Мора

Хороша швидкість, але це важко кодує залежно від голки, що закінчується _. Чи є загальна версія?
Тоддмо

0

Я думаю, що substr_replace робить все, що ви хочете, і ви можете обмежити свою заміну частиною рядка: http://nl3.php.net/manual/en/function.substr-replace.php (Це дозволить вам дивитися лише на початок рядка.)

Ви можете використовувати параметр count str_replace ( http://nl3.php.net/manual/en/function.str-replace.php ), це дозволить вам обмежити кількість замін, починаючи зліва, але це не буде примушувати його бути на початку.


1
substr_replaceзамінить символи в заданому діапазоні незалежно від того, чи є вони префіксом, який ви хочете видалити, чи чимось іншим. ОП хоче видалити bla_"лише в тому випадку, якщо він знайдений на початку рядка".
Олів'є «Ельбаум» Шерлер

0

Приємна швидкість, але це важко кодується залежно від голки, що закінчується символом _. Чи є загальна версія? - Тоддмо 29 червня о 23:26

Загальна версія:

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

Деякі орієнтири:

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

На моєму досить старому домашньому ПК:

$ php bench.php

Виходи:

   strpos+strlen : 0.158388 s
         explode : 0.126772 s

0

Ось ще швидший підхід:

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

0

Це видалить першу відповідність, де б не було знайдено, тобто, початок, середина чи кінець.

$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 ] )

тепер робить те, що ти хочеш.

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

7
Очікується str_replace(), що $countпараметр функції буде змінною, переданою за посиланням, щоб містити кількість знайдених замін, а не обмежувати кількість замін.
AL X X

-6

Видалити www. від початку рядка, це найпростіший спосіб (ltrim)

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

8
Другий параметр - це карта символів, яку потрібно видалити з лівої частини рядка ( php.net/manual/function.ltrim.php ). Тому: ltrim($a, "w.");зробить цю роботу лише в тому випадку, якщо домен не починається з "w". ltrim ('m.google.com', ".omg")результати в le.com.
фрагментарнареальність

але це вирішує конкретну проблему питання, +1
chullian

1
це дійсно вирішує конкретну проблему, яку він створив для своєї відповіді - не проблему питання. навіть якщо ви б пішли з ним ltrim, він використовується неправильно. другий параметр - це список символів, які слід обрізати; тому одного "w."було б достатньо.
фрагментарна

Я думаю, ІМХО, це правильно і для питання, і для проблеми.
abkrim

2
Після тесту з декількома тестами міняйте свою думку .... не працюйте на питання щодо будь-яких ситуацій
abkrim
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.