вкладка гитара php regex (вкладки или табулатура, тип нотной записи) - PullRequest
6 голосов
/ 03 июня 2010

Я нахожусь в процессе создания в PHP конвертера табачных гитар в rtttl (Ring Tone Text Transfer Language). Чтобы подготовить вкладку гитары для конвертации в rtttl, я сначала удаляю все комментарии (комментарии отмечены # и заканчиваются - #), затем у меня есть несколько строк, которые задают темп, отмечают настройку и определяют несколько инструментов (Tempo 120 \ nDefine Guitar 1 \ nDefine Bass 1 и т. д. и т. д.), которые вынимаются из вкладки и откладываются для дальнейшего использования.

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

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

Пример 1, вкладка «Стандартная гитара»:

 |Guitar 1
e|--------------3-------------------3------------|
B|------------3---3---------------3---3----------|
G|----------0-------0-----------0-------0--------|
D|--------0-----------0-------0-----------0------|
A|------2---------------2---2---------------2----|
E|----3-------------------3-------------------3--|

Пример 2, вкладка «Соединение»:

 |Guitar 1
e|--------------3-------------------3------------|
B|------------3---3---------------3---3----------|
G|----------0-------0-----------0-------0--------|
D|--------0-----------0-------0-----------0------|
A|------2---------------2---2---------------2----|
E|----3-------------------3-------------------3--|
 |
 |
 |Bass 1
G|----------0-------0-----------0-------0--------|
D|--------2-----------2-------2-----------2------|
A|------3---------------3---3---------------3----|
E|----3-------------------3-------------------3--|

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

Как только вкладки окажутся в массиве, я буду просматривать их по одной строке за раз и преобразовывать их в строки rtttl (взорванные на каждой новой строке "\ n").

Я не хочу разделять вкладки гитары в документе с помощью разнесения "\ n \ n" или чего-то подобного, потому что он не идентифицирует вкладку гитары, а скорее идентифицирует пространство между вкладками, а не на вкладках сами по себе.

Я вот уже неделю как берись с этим, и это единственная серьезная задержка, которая у меня есть. Все остальное довольно просто.

На данный момент я пробовал много вариантов шаблона регулярных выражений. Вот один из самых последних тестовых образцов:

<?php
$t = "
 |Guitar 1
e|--------------3-------------------3------------|
B|------------3---3---------------3---3----------|
G|----------0-------0-----------0-------0--------|
D|--------0-----------0-------0-----------0------|
A|------2---------------2---2---------------2----|
E|----3-------------------3-------------------3--|

 |Guitar 1
e|--------------3-------------------3------------|
B|------------3---3---------------3---3----------|
G|----------0-------0-----------0-------0--------|
D|--------0-----------0-------0-----------0------|
A|------2---------------2---2---------------2----|
E|----3-------------------3-------------------3--|
 |
 |
 |Bass 1
G|----------0-------0-----------0-------0--------|
D|--------2-----------2-------2-----------2------|
A|------3---------------3---3---------------3----|
E|----3-------------------3-------------------3--|

";

preg_match_all("/^.*?(\\|).*?(\\|)/is",$t,$p);
print_r($p);

?>

Стоит также отметить, что внутри вкладок, где расположены тире и #, также могут присутствовать любые варианты букв, цифр и знаков препинания. В начале каждой строки отмечается настройка каждой строки одним из следующих символов без учета регистра: a, a #, b, c, c #, d, d #, e, f, f #, g или g.

Заранее спасибо за помощь в решении этой самой сложной проблемы.

Ответы [ 4 ]

5 голосов
/ 03 июня 2010

Мне очень нравится этот вопрос :-P. мне было весело выяснить это.
Вот что я получил:

<?php
$t = <<<EOD
 |Guitar 1
e|--------------3-------------------3------------|
B|------------3---3---------------3---3----------|
G|----------0-------0-----------0-------0--------|
D|--------0-----------0-------0-----------0------|
A|------2---------------2---2---------------2----|
E|----3-------------------3-------------------3--|

 |Guitar 1
e|--------------3-------------------3------------|
B|------------3---3---------------3---3----------|
G|----------0-------0-----------0-------0--------|
D|--------0-----------0-------0-----------0------|
A|------2---------------2---2---------------2----|
E|----3-------------------3-------------------3--|
 |
 |
 |Bass 1
G|----------0-------0-----------0-------0--------|
D|--------2-----------2-------2-----------2------|
A|------3---------------3---3---------------3----|
E|----3-------------------3-------------------3--|

EOD;


GetTabs($t);

function GetTabs($tabString) {
    $tabs = array();
    $tabcount = 0;
    $instrumentcount = 0;
    $tabline = 0;

    $tabStringArray = explode("\n", $tabString);

    foreach ($tabStringArray as $tabStringRow) {

        if (preg_match  ('/^(?<snaretuningprefix>[bgdaeBGDAE#])+\|(?<tabline>[0-9-]+)\|/', $tabStringRow)) {
            //Matches a tab line
            //The tabline group can be expanded with characters for hammer on's, pull off's and whatnot
            $tabs[$tabcount][$instrumentcount-1][$tabline] = $tabStringRow;
            $tabline++;
            continue;
        }

        if (preg_match  ('/^\s\|\s+/', $tabStringRow, $matches)) {
            //Matches ' |'
            //Continuation of tab do nothing
            continue;
        }

        if (preg_match  ('/^\s\|(?<instrument>[A-z0-9\s]+)/', $tabStringRow, $matches)) {
            //Matches an instrument line ' |Guitar 1'

            $tabs[$tabcount][$instrumentcount]['instrumentname'] = $matches['instrument'];
            $instrumentcount++;
            $tabline = 0;
            continue;
        }

        if (preg_match  ('/^\s+/', $tabStringRow)) {
            //Matches empty line
            //new tab

            $tabcount++;
            $instrumentcount = 0;

            continue;
        }

    }

    print_r($tabs);
}


?>

Функция несколько прокомментирована, я думаю, ее не так сложно читать.
это выводит:

Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [instrumentname] => Guitar 1
                    [0] => e|--------------3-------------------3------------|
                    [1] => B|------------3---3---------------3---3----------|
                    [2] => G|----------0-------0-----------0-------0--------|
                    [3] => D|--------0-----------0-------0-----------0------|
                    [4] => A|------2---------------2---2---------------2----|
                    [5] => E|----3-------------------3-------------------3--|
                )

        )

    [1] => Array
        (
            [0] => Array
                (
                    [instrumentname] => Guitar 1
                    [0] => e|--------------3-------------------3------------|
                    [1] => B|------------3---3---------------3---3----------|
                    [2] => G|----------0-------0-----------0-------0--------|
                    [3] => D|--------0-----------0-------0-----------0------|
                    [4] => A|------2---------------2---2---------------2----|
                    [5] => E|----3-------------------3-------------------3--|
                )

            [1] => Array
                (
                    [instrumentname] => Bass 1
                    [0] => G|----------0-------0-----------0-------0--------|
                    [1] => D|--------2-----------2-------2-----------2------|
                    [2] => A|------3---------------3---3---------------3----|
                    [3] => E|----3-------------------3-------------------3--|
                )

        )

)
1 голос
/ 03 июня 2010
<?php
$t = <<<EOD
 |Guitar 1
e|--------------3-------------------3------------|
B|------------3---3---------------3---3----------|
G|----------0-------0-----------0-------0--------|
D|--------0-----------0-------0-----------0------|
A|------2---------------2---2---------------2----|
E|----3-------------------3-------------------3--|

 |Guitar 1
e|--------------3-------------------3------------|
B|------------3---3---------------3---3----------|
G|----------0-------0-----------0-------0--------|
D|--------0-----------0-------0-----------0------|
A|------2---------------2---2---------------2----|
E|----3-------------------3-------------------3--|
 |
 |
 |Bass 1
G|----------0-------0-----------0-------0--------|
D|--------2-----------2-------2-----------2------|
A|------3---------------3---3---------------3----|
E|----3-------------------3-------------------3--|

EOD;

$t = preg_replace('/\r\n?/', "\n", $t); //normalize line endings

$te = explode("\n", $t);

$out = array();
$cur_inst = "";
$trim = false;
$lastlines = array();
$i = 0;
foreach ($te as $line) {
    if (preg_match("/^\\s\\|(\\w+ \\d+)\$/", $line, $matches)) {
        if ($matches[1] == $cur_inst) {
            $trim = true;
        }
        else {
            $out[$i++] = $line;
            $trim = false;
            $lastline = array();
            $cur_inst = $matches[1];
        }
    }
    elseif (empty($line) || preg_match("/^\\s\\|\$/", $line)) {
        if (!preg_match("/^\\s\\|\$/", end($out)))
            $out[$i++] = $line;
    }
    elseif (preg_match("/^([a-zA-Z])\\|(.*)\$/", $line, $matches)) {
        if ($trim) {
            if (array_key_exists($matches[1], $lastlines)) {
                $oldi= $lastlines[$matches[1]];
                $out[$oldi] = rtrim($out[$oldi], "|") . $matches[2];
            }
            else {
                die("unexpected line: $line");
            }
        }
        else {
            $lastlines[$matches[1]] = $i;
            $out[$i++] = $matches[0];
        }
    }
    else {
        die("unexpected line: $line");
    }
}

$t = implode(PHP_EOL, $out);

echo $t;

дает

 |Guitar 1
e|--------------3-------------------3--------------------------3-------------------3------------|
B|------------3---3---------------3---3----------------------3---3---------------3---3----------|
G|----------0-------0-----------0-------0------------------0-------0-----------0-------0--------|
D|--------0-----------0-------0-----------0--------------0-----------0-------0-----------0------|
A|------2---------------2---2---------------2----------2---------------2---2---------------2----|
E|----3-------------------3-------------------3------3-------------------3-------------------3--|

 |
 |Bass 1
G|----------0-------0-----------0-------0--------|
D|--------2-----------2-------2-----------2------|
A|------3---------------3---3---------------3----|
E|----3-------------------3-------------------3--|

Если вы предпочитаете, вы можете перебирать массив $out.

1 голос
/ 03 июня 2010

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

^[^|\r\n]+\|([^|\r\n]+)$\r?\n  # match the line that contains the instrument name
                               # and capture this in backreference 1
(                              # capture the block of lines that follows
 (?:                           # repeat this for each line
  ^[^|\r\n]+                   # everything up to the first |
  \|                           # |
  [^|\r\n]+                    # everything up to the next |
  \|                           # |
  \r?\n                        # newline
 )+                            # at least once
)                              # end capture

В PHP:

preg_match_all('/^[^|\r\n]+\|([^|\r\n]+)$\r?\n((?:^[^|\r\n]+\|[^|\r\n]+\|\r?\n)+)/im', $subject, $result, PREG_PATTERN_ORDER);
for ($i = 0; $i < count($result[0]); $i++) {
    # Matched text = $result[0][$i];
}

Каждый матч будет иметь вид

 |Bass 1
G|----------0-------0-----------0-------0--------|
D|--------2-----------2-------2-----------2------|
A|------3---------------3---3---------------3----|
E|----3-------------------3-------------------3--|

и все остальное между этими блоками будет игнорироваться.

0 голосов
/ 03 июня 2010

^ в вашем регулярном выражении не позволит переключателю / s делать то, что вы хотите.

Кроме того, preg_match_all будет возвращать много повторяющихся «совпадений», потому что вы используете () группирование. Если вы планируете использовать preg_match_all () в файле с несколькими вкладками, выделение реальных совпадений может оказаться затруднительным с этими дубликатами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...