используйте preg_split для разделения аккордов и слов

Я работаю над небольшим фрагментом кода, воспроизводящим вкладки сонга, но я застрял в проблеме.

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

Каждый кусок был бы таким:

$line_chunk = array( 0 => //part of line containing one or several chords 1 => //part of line containing words ); 

Они должны оставаться «сгруппированными». Я имею в виду, что он должен расколоться только тогда, когда функция достигает «предела» между аккордами и словами.

Думаю, я должен использовать preg_split для достижения этого. Я сделал несколько тестов, но мне удалось разделить аккорды, а не «группы» аккордов:

 $line_chunks = preg_split('/(\[[^]]*\])/', $line, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); 

Эти примеры показывают, что я хотел бы получить:

на строке, не содержащей аккордов:

 $input = '{intro}'; $results = array( array( 0 => null, 1 => '{intro} ) ); 

на линии, содержащей только аккорды:

 $input = '[C#] [Fm] [C#] [Fm] [C#] [Fm]'; $results = array( array( 0 => '[C#] [Fm] [C#] [Fm] [C#] [Fm]', 1 => null ) ); 

на строке, содержащей оба:

 $input = '[C#]I'm looking for [Fm]you [G#]'; $results = array( array( 0 => '[C#]', 1 => 'I'm looking for' ), array( 0 => '[Fm]', 1 => 'you ' ), array( 0 => '[G#]', 1 => null ), ); 

Любые идеи о том, как это сделать?

Благодаря !

preg_split – это не путь. В большинстве случаев, когда у вас есть сложная задача разделения, чтобы добиться этого, проще попытаться сопоставить то, что вас интересует, вместо того, чтобы пытаться разделить с помощью нелегкого определения разделителя.

Подход preg_match_all :

 $pattern = '~ \h* (?| # open a "branch reset group" ( \[ [^]]+ ] (?: \h* \[ [^]]+ ] )*+ ) # one or more chords in capture group 1 \h* ( [^[\n]* (?<=\S) ) # eventual lyrics (group 2) | # OR () # no chords (group 1) ( [^[\n]* [^\s[] ) # lyrics (group 2) ) # close the "branch reset group" ~x'; if (preg_match_all($pattern, $input, $matches, PREG_SET_ORDER)) { $result = array_map(function($i) { return [$i[1], $i[2]]; }, $matches); print_r($result); } 

демонстрация

Группа сброса филиалов сохраняет ту же нумерацию групп для каждой ветви.

Примечание: не стесняйтесь добавлять:

 if (empty($i[1])) $i[1] = null; if (empty($i[2])) $i[2] = null; 

в функции карты, если вы хотите получить пустые элементы вместо пустых элементов.

Примечание2: если вы работаете по строкам, вы можете удалить \n из шаблона.

Я бы пошел с PHP explode :

 /* * Process data */ $input = '[C#]I'm looking for [Fm]you [G#]'; $parts = explode("[", $input); $results = array(); foreach ($parts as $item) { $pieces = explode("]", $item); if (count($pieces) < 2) { $arrayitem = array( "Chord" => $pieces[0], "Lyric" => ""); } else { $arrayitem = array( "Chord" => $pieces[0], "Lyric" => $pieces[1]); } $results[] = $arrayitem; } /* * Echo results */ foreach ($results as $str) { echo "Chord: " . $str["Chord"]; echo "Lyric: " . $str["Lyric"]; } 

Boudaries не тестируются в коде, а также в остальных пробелах, но это основа для работы.