php regex 吉他谱(谱表或指法谱,一种乐谱)

发布于 2024-09-04 06:44:59 字数 2662 浏览 3 评论 0原文

我正在用 PHP 创建一个吉他标签到 rtttl(铃声文本传输语言)转换器。为了准备用于 rtttl 转换的吉他标签,我首先删除所有注释(由 #- 注释并以 -# 结尾的注释),然后我有几行设置速度、注意调音并定义多个乐器(速度 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。

预先感谢您帮助解决这个最困难的问题。

I am in the process of creating a guitar tab to rtttl (Ring Tone Text Transfer Language) converter in PHP. In order to prepare a guitar tab for rtttl conversion I first strip out all comments (comments noted by #- and ended with -#), I then have a few lines that set tempo, note the tunning and define multiple instruments (Tempo 120\nDefine Guitar 1\nDefine Bass 1, etc etc) which are stripped out of the tab and set aside for later use.

Now I essentially have nothing left except the guitar tabs. Each tab is prefixed with it's instrument name in conjunction with the instrument name noted prior.

Some times we have tabs for 2 separate instruments that are linked because they are to be played together, ie a Guitar and a Bass Guitar playing together.

Example 1, Standard Guitar Tab:

 |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--|

Example 2, Conjunction Tab:

 |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--|

I have considered other methods of identifying the tabs with no solid results. I am hoping that someone who does regular expressions could help me find a way to identify a single guitar tab and if possible also be able to match a tab with multiple instruments linked together.

Once the tabs are in an array I will go through them one line at a time and convert them into rtttl lines (exploded at each new line "\n").

I do not want to separate the guitar tabs in the document via explode "\n\n" or something similar because it does not identify the guitar tab, rather, it is identifying the space between the tabs - not on the tabs themselves.

I have been messing with this for about a week now and this is the only major hold up I have. Everything else is fairly simple.

As of current, I have tried many variations of the regex pattern. Here is one of the most recent test samples:

<?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);

?>

It is also worth noting that inside the tabs, where the dashes and #'s are, you may also have any variation of letters, numbers and punctuation. The beginning of each line marks the tuning of each string with one of the following case insensitive: a,a#,b,c,c#,d,d#,e,f,f#,g or g.

Thanks in advance for help with this most difficult problem.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

年华零落成诗 2024-09-11 06:44:59

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

        )

)

I really like this question :-P. i had fun figuring this one out.
Here's what I got:

<?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);
}


?>

The function is commented somewhat, it's not that hard to read I think.
this outputs:

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--|
                )

        )

)
纵性 2024-09-11 06:44:59
<?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 数组。

<?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;

gives

 |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--|

If you prefer, you can iterate over the $out array.

清引 2024-09-11 06:44:59

我不完全确定你到底是什么意思,但如果你想按工具分隔选项卡,请尝试以下操作:

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

,并且这些块之间的所有其他内容都将被忽略。

I'm not entirely sure what exactly you mean, but if you want to separate tabs by instrument, try this:

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

In 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];
}

Each match will be of the form

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

and everything else between those blocks will be ignored.

止于盛夏 2024-09-11 06:44:59

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

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

The ^ in your regex will prevent the /s switch from doing what you want.

Also, preg_match_all is going to return a lot of duplicate "matches" because you are using ( ) grouping. If you plan to use preg_match_all() on a file with multiple tabs, isolating real matches might be difficult with those duplicates.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文