Как заставить эту странную строку взорваться в PHP?


У меня есть строка, подобная следующей

DAS-1111[DR-Helpfull-R]-RUN--[121668688374]-N-[+helpfull_+string]

Приведенная выше строка является своего рода отформатированной в группах, которая выглядит следующим образом:

A-B[C]-D-E-[F]-G-[H]

Я думаю, что мне нравится обрабатывать некоторые из этих групп, и мне нравится делать что-то вроде взрыва.

Я говорю "нравится", потому что я попробовал этот код:

$string = 'DAS-1111[DR-Helpfull-R]-RUN--[121668688374]-N-[+helpfull_+string]';
$parts = explode( '-', $string );
print_r( $parts );

И я получаю следующий результат:

Array
(
    [0] => DAS
    [1] => 1111[DR
    [2] => Helpfull
    [3] => R]
    [4] => RUN
    [5] => 
    [6] => [121668688374]
    [7] => N
    [8] => [+helpfull_+string]
)

Что это не то, что мне нужно.

Что мне нужно, так это следующий вывод:

Array
(
    [0] => DAS
    [1] => 1111[DR-Helpfull-R]
    [2] => RUN
    [3] => 
    [4] => [121668688374]
    [5] => N
    [6] => [+helpfull_+string]
)

Может кто-нибудь, пожалуйста, предложите хороший и элегантный способ взорвать эту строку так, как мне это нужно?

Что я забыл упомянуть, так это то, что строка может содержать больше или меньше групп. Примеры:

DAS-1111[DR-Helpfull-R]-RUN--[121668688374]-N-[+helpfull_+string]
DAS-1111[DR-Helpfull-R]-RUN--[121668688374]
DAS-1111[DR-Helpfull-R]-RUN--[121668688374]-N-[+helpfull_+string]-anotherPart

Обновление 1

Как упоминал @axiac, preg_split может выполнить эту работу. Но не могли бы вы, пожалуйста, помочь с регулярным выражением сейчас?

Я попробовал это, но, похоже, это неверно:

(?!\]\-)\-

Author: Salman A, 2016-04-15

3 answers

Код:

$str = 'DAS-1111[DR-Helpfull-R]-RUN--[121668688374]-N-[+helpfull_+string]';
$re  = '/([^-[]*(?:\[[^\]]*\])?[^-]*)-?/';

$matches = array();
preg_match_all($re, $str, $matches);
print_r($matches[1]);

Его вывод:

Array
(
    [0] => DAS
    [1] => 1111[DR-Helpfull-R]
    [2] => RUN
    [3] =>
    [4] => [121668688374]
    [5] => N
    [6] => [+helpfull_+string]
    [7] =>
)

В позиции 7 на выходе есть дополнительное пустое значение. Это появляется из-за квантора повторений с нулем или одним (?), размещенного в конце regex. Квантификатор необходим, потому что без него последний фрагмент (с индексом 6) не сопоставляется.

Вы можете удалить ? после последнего - и задать таким образом, чтобы тире (-) всегда совпадало. В этом случае вы должны добавить дополнительный - к своим входным данным строка.

Регулярное выражение

(              # start of the 1st subpattern
               # the captured value is returned in $matches[1]
  [^-[]*       # match any character but '-' and '[', zero or more times
  (?:          # start of a non-capturing subpattern
    \[         # match an opening square bracket ('[')
    [^\]]*     # match any character but ']', zero or more times
    \]         # match a closing square bracket (']')
  )?           # end of the subpattern; it is optional (can appear 0 or 1 times)
  [^-]*        # match any character but '-', zero or more times
)              # end of the 1st subpattern
-?             # match an optional dash ('-')
 5
Author: axiac, 2016-04-15 11:56:36

Вместо того, чтобы взрываться, вы должны попытаться соответствовать следующему шаблону:

(?:^|-)([^-\[]*(?:\[[^\]]+\])?)

Вот пример:

$regex = '/(?:^|-)([^-\[]*(?:\[[^\]]+\])?)/';
$tests = array(
    'DAS-1111[DR-Helpfull-R]-RUN--[121668688374]-N-[+helpfull_+string]',
    'DAS-1111[DR-Helpfull-R]-RUN--[121668688374]',
    'DAS-1111[DR-Helpfull-R]-RUN--[121668688374]-N-[+helpfull_+string]-anotherPart'
);
foreach ($tests as $test) {
    preg_match_all($regex, $test, $result);
    print_r($result[1]);
}

Вывод:

// DAS-1111[DR-Helpfull-R]-RUN--[121668688374]-N-[+helpfull_+string]
Array
(
    [0] => DAS
    [1] => 1111[DR-Helpfull-R]
    [2] => RUN
    [3] => 
    [4] => [121668688374]
    [5] => N
    [6] => [+helpfull_+string]
)

// DAS-1111[DR-Helpfull-R]-RUN--[121668688374]
Array
(
    [0] => DAS
    [1] => 1111[DR-Helpfull-R]
    [2] => RUN
    [3] => 
    [4] => [121668688374]
)

// DAS-1111[DR-Helpfull-R]-RUN--[121668688374]-N-[+helpfull_+string]-anotherPart
Array
(
    [0] => DAS
    [1] => 1111[DR-Helpfull-R]
    [2] => RUN
    [3] => 
    [4] => [121668688374]
    [5] => N
    [6] => [+helpfull_+string]
    [7] => anotherPart
)
 2
Author: Salman A, 2016-04-15 12:38:23

Этот случай идеально подходит для метода (*SKIP)(*FAIL). Вы хотите разделить свою строку на дефисы, если они не заключены в квадратные скобки.

Легко. Просто дисквалифицируйте эти дефисы в качестве разделителей следующим образом:

Шаблон: ~\[[^]]+\](*SKIP)(*FAIL)|-~ ( Демонстрация шаблона)

Код: ( Демонстрационный)

$strings=['DAS-1111[DR-Helpfull-R]-RUN--[121668688374]-N-[+helpfull_+string]',
          'DAS-1111[DR-Helpfull-R]-RUN--[121668688374]',
          'DAS-1111[DR-Helpfull-R]-RUN--[121668688374]-N-[+helpfull_+string]-anotherPart'];

foreach($strings as $string){
    var_export(preg_split('~\[[^]]+\](*SKIP)(*FAIL)|-~',$string));
    echo "\n\n";
}

Вывод:

array (
  0 => 'DAS',
  1 => '1111[DR-Helpfull-R]',
  2 => 'RUN',
  3 => '',
  4 => '[121668688374]',
  5 => 'N',
  6 => '[+helpfull_+string]',
)

array (
  0 => 'DAS',
  1 => '1111[DR-Helpfull-R]',
  2 => 'RUN',
  3 => '',
  4 => '[121668688374]',
)

array (
  0 => 'DAS',
  1 => '1111[DR-Helpfull-R]',
  2 => 'RUN',
  3 => '',
  4 => '[121668688374]',
  5 => 'N',
  6 => '[+helpfull_+string]',
  7 => 'anotherPart',
)
 1
Author: mickmackusa, 2018-01-25 06:34:37