php regex吉他标签(标签或指法,一种音乐符号)

时间:2010-06-03 17:59:03

标签: php regex tabs

我正在使用PHP为rtttl(铃声文本传输语言)转换器创建吉他标签。为了准备一个用于rtttl转换的吉他标签,我首先删除所有注释(注释为# - 并以 - #结尾),然后我有几行设置速度,注意调整和定义多个乐器(Tempo 120 \ n定义吉他1 \ n定义低音1等等,从标签中剥离并放在一边供以后使用。

现在我除了吉他标签之外什么都没有留下。每个标签都带有它的仪器名称和前面提到的仪器名称。

有些时候我们有两个独立乐器的标签,因为它们要一起演奏,即一起演奏的吉他和低音吉他。

示例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 个答案:

答案 0 :(得分:5)

我真的很喜欢这个问题:-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 :(得分:1)

<?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数组。

答案 2 :(得分:1)

我不完全确定你究竟是什么意思,但是如果你想用仪器分隔标签,试试这个:

^[^|\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--|

将忽略这些块之间的所有其他内容。

答案 3 :(得分:0)

正则表达式中的^会阻止/ s开关执行您想要的操作。

此外,preg_match_all将返回大量重复的“匹配”,因为您正在使用()分组。如果您计划在具有多个选项卡的文件上使用preg_match_all(),那么对于那些重复项,隔离实际匹配可能会很困难。