Лучший способ справиться с разделением пути Windows или Linux

#php #regex #preg-split

#php #регулярное выражение #preg-split

Вопрос:

У меня есть две строки:

 C:UsersBobMy Documents
/Users/Bob/Documents
  

Мне удалось вызвать это регулярное выражение:

 preg_split('/(?<=[/\])(?![/\])/', $string)
  

это вернет

 Array
(
    [0] => C:
    [1] => Users
    [2] => Bob
    [3] => My Documents
)

Array
(
    [0] => /
    [1] => Users/
    [2] => Bob/
    [3] => Documents
)
  

Тем не менее, я ищу

 Array
(
    [0] => C:
    [1] => Users
    [2] => Bob
    [3] => My Documents
)

Array
(
    [0] => /
    [1] => Users
    [2] => Bob
    [3] => Documents
)
  

т.е. Конечные косые черты отсутствуют в исправленных массивах

Комментарии:

1. Есть какая-нибудь причина, по которой вы не можете просто разделить его на / или ` and add DIRECTORY_SEPARATOR` до первого индекса?

2. Вы можете разделить с разделителем или без него, но не с первой частью и без других частей. Пожалуйста, прочтите руководство пользователя: php.net/manual/en/function.preg-split.php

3. @Lekensteyn Я полагаю, вы имеете в виду предопределенную константу PHP? Несмотря на хороший подход, пути не имеют отношения к размещенной среде

Ответ №1:

Почему бы просто не проверить наличие «/» или «», а затем использовать explode с соответствующим разделителем?

 <?php
$s1 = 'C:\Users\Bob\My Documents';
$s2 = '/Users/Bob/Documents';

function mySplit($s) {
    if(strpos($s, '/') !== false) {
        $d = '/';
    }elseif(strpos($s,'\') !== false) {
        $d = '\';
    }else {
        throw new Exception('Valid delimiter not found.');
    }

    $ret = explode($d, $s);
    $ret[0] .= $d;

    return $ret;
}

echo '<pre>' . print_r(mySplit($s1),true) . '</pre>';
echo '<pre>' . print_r(mySplit($s2),true) . '</pre>';
?>
  

(Обновлено с немного более аккуратной версией)

Комментарии:

1. Я использовал strpos() вместо strstr() . Согласно руководству по PHP: Примечание: Если вы хотите только определить, встречается ли конкретная игла в стоге сена, вместо этого используйте более быструю и менее ресурсоемкую функцию strpos() .

Ответ №2:

С помощью следующего кода вы получите то, что хотите, но первый ключ также будет без косой черты:

 preg_split('#(?<=)[/\]#', $string);
  

Ответ №3:

 $dirs = explode(DIRECTORY_SEPARATOR, $string);
$dirs[0] .= DIRECTORY_SEPARATOR;
  

Комментарии:

1. Мне нравится, насколько это коротко. К сожалению, он неправильно анализирует путь в стиле Windows, когда он выполняется на компьютере с Linux (и наоборот).

2. @MarkBiek Да, но это очень редкая необходимость анализировать путь к не хост-машине. По крайней мере, по моему опыту 🙂

3. Похоже, в случае с Вантелом ему приходится анализировать пути, не связанные с хост-средой.

4. @Vanthel, вы, безусловно, можете это сделать, если уверены в своих вводных данных.

5. @Vanthel Да, это будет работать, за исключением того, что вы должны протестировать его следующим образом: $delim = ((strpos($string, '/') !== false) ? '/' : '\') потому что ноль тоже принимает значение false.

Ответ №4:

Я знаю, что вы уже приняли ответ, но есть очень простое, однострочное решение этой проблемы, которое я регулярно использую, и я чувствую, что его нужно опубликовать здесь:

 $pathParts = explode('/', rtrim(str_replace('\', '/', $path)));
  

Это заменяет обратную косую черту прямой косой чертой, обрезает любые конечные косые черты и взрывается. Это можно сделать безопасно, поскольку пути Windows не могут содержать косых черт, а пути Linux не могут содержать обратных косых черт.

Результирующий массив выглядит не совсем так, как вы описали выше — корневая часть пути не будет содержать косую черту, но в любом случае он лучше представлен таким образом. Это потому, что корень пути (т. Е. C: Или ‘/’) На самом деле не так полезен при хранении с косыми чертами. В результате этого вы можете вызвать implode('/', $pathParts); и получить действительный обратный путь, тогда как с вашим массивом вы получите дополнительную косую черту в корне. Кроме того, UsersUserMy Documents (без буквы диска) по-прежнему является допустимым путем в Windows, он просто подразумевает текущий рабочий объем.

Комментарии:

1. Спасибо за вклад. И отличное объяснение. Я согласен, что в большинстве случаев этот ответ более чем уместен, и я не сомневаюсь, что когда-нибудь воспользуюсь этим. Но в моем случае исходный ответ по-прежнему ближе всего к тому, что мне требуется (где полезен root, отсюда и мои усилия по его сохранению).