За последние 24 часа нас посетили 21384 программиста и 1694 робота. Сейчас ищут 1873 программиста ...

Проверка строк на содержание определенных сочетаний символов

Тема в разделе "Регулярные выражения", создана пользователем PCSpeaker, 20 июн 2009.

  1. PCSpeaker

    PCSpeaker Активный пользователь

    С нами с:
    26 дек 2007
    Сообщения:
    84
    Симпатии:
    0
    Хочу сделать, чтобы программа определяла строки в которых содержатся аккорды, для последующей их подсветки.
    К примеру строка "Am Dm B Gm" признавалась аккордной, а строка "I Am Boy" нет. При этом порядок может быть разный "Dm B" или "Gm A" и т.д.

    Ниже прилагают то что удалось сделать мне. Но во-первых, оно почему-то не работает в некоторых строках (быть может они содержат какие-нибудь символы табуляции, переноса строк или еще что-нибудь непечатаемое), а во-вторых способ сам по себе очень громоздкий у меня вышел. Быть может как-то регулярным выражением можно проще это описать? Заранее спасибо.

    PHP:
    1.  
    2. <?php
    3. $txt=nl2br($txt);
    4.         $textstr=explode("<br />", $txt);
    5.         $c=count($textstr);
    6.         for ($i = 0; $i < $c; $i++)
    7.         {  
    8.            
    9.             $test=0;
    10.             $textstr[$i];
    11.             $cc=count($textstr);
    12.             $textstritems=explode(" ", $textstr[$i]);
    13.             for ($j = 0; $j < $cc; $j++) {
    14.                 if (preg_match("/^Am|B|Gm|D#|Dm$/i",$textstritems[$j]) or $textstritems[$j]=="") {
    15.                 //echo $j.") ".$textstritems[$j]."<br>";
    16.                 $test=1;
    17.                     //echo "<br>aaa<br>";
    18.                 }
    19.                 else {$test=0; break;}
    20.             }
    21.             if ($test==0) {
    22.                 $txtout.=$textstr[$i]."<br>";
    23.             }
    24.             else {
    25.                 for ($j = 0; $j < $cc; $j++) {
    26.                     $txtout.="<a href=aa>".$textstritems[$j]."</a> ";
    27.                 }
    28.                 $txtout.="<br>";
    29.             }
    30.         }
    31.         return $txtout;
    32. ?>
    33.  
     
  2. Volt(220)

    Volt(220) Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1.640
    Симпатии:
    1
    Ошибка в строках 9-11.
    9 строка - ни чего не делает.
    10 и 11 надо поменять местами и наверное
    Код (Text):
    1. $cc=count($textstr);
    надо заменить на
    Код (Text):
    1. $cc=count($textstritems);
    А вообще интересная задача. Ведь кроме простых A, Am есть еще всякие Asus4, Am7+5 и т. д. :)

    Думаю имеет смысл изменить код:
    PHP:
    1. <?php
    2. $test=0;
    3. $cc=count($textstr);
    4. $textstritems=explode(" ", $textstr[$i]);
    5.  for ($j = 0; $j < $cc; $j++) {
    6.                   if (preg_match("/^Am|B|Gm|D#|Dm$/i",$textstritems[$j]) or $textstritems[$j]=="") {
    7.                   //echo $j.") ".$textstritems[$j]."<br>";
    8.                   $test=1;
    9.                       //echo "<br>aaa<br>";
    10.                   }
    11.                   else {$test=0; break;}
    12.               }
    13. ?>
    на:
    PHP:
    1. <?php
    2. $test=1;
    3. $textstritems=explode(" ", $textstr[$i]);
    4. $cc=count($textstritems);
    5.  for ($j = 0; $j < $cc; $j++) {
    6.                   if (!isAccord($textstritems[$j])) {
    7.                        $test=0; break;
    8.                   }
    9.  }
    10. ?>
    И соответственно расписать функцию isAccord($acc)
     
  3. PCSpeaker

    PCSpeaker Активный пользователь

    С нами с:
    26 дек 2007
    Сообщения:
    84
    Симпатии:
    0
    Упс. Наглядный пример того, что программистов нельзя отвлекать во время составления кода, иначе получаются такие вот глупые ляпы) Спасибо что нашли ошибку.
    Пишу сайт вместе с человеком который хорошо в этом разибрается. Есть база из 234 аккордов. Гложет только меня сомнение, что сравнение каждого слова текста с таким количеством элементов будет хорошенько грузить сайт... Хотя может и не очень.
    Попробую завтра что-нибудь состряпать) Просмотрел много зарубежных гитарных сайтов и такое ощущение, что либо в каждой песне модератор вручную аккорды расставляет, либо там какие-то гениальные алгоритмы которые отличают аккорды в любом месте текста.
     
  4. Black Raven

    Black Raven Активный пользователь

    С нами с:
    8 июн 2009
    Сообщения:
    25
    Симпатии:
    0
    А в чем сложность?

    http://amdm.ru/cgen/

    Как строится аккорд? - Сначала нота, потом может быть бемоль или диез (а может и не быть), потом может быть то что на амдм назвали "тип" (я без муз. образования, поэтому как это правильно называется не в курсе).

    Надо просто внимательней почитать как составляются регулярные выражения, например на http://www.pcre.ru/ ну или в вики
     
  5. PCSpeaker

    PCSpeaker Активный пользователь

    С нами с:
    26 дек 2007
    Сообщения:
    84
    Симпатии:
    0
    Проблема с диезом. Просто диез он не понимает, понимает зато \x23, но только если вокруг него не стоят \b \b (границы слова)
    Вот к примеру все вариации ноты A. Работает всё кроме A#
    Код (Text):
    1. \b(A|Ab|A\x23)(5|m||6|m6|7|m7|\+7|m\+7|sus2|sus4|9|m9)\b
     
  6. TheShock

    TheShock Активный пользователь

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    что значит "не понимает диез" ? Экранировать пробовали?
     
  7. Black Raven

    Black Raven Активный пользователь

    С нами с:
    8 июн 2009
    Сообщения:
    25
    Симпатии:
    0
    А зачем делать диез и бемоль частью ноты? Ну и попробовать экранировать диез.
     
  8. PCSpeaker

    PCSpeaker Активный пользователь

    С нами с:
    26 дек 2007
    Сообщения:
    84
    Симпатии:
    0
    Первым же делом.
    Код (Text):
    1. \b(A|Ab|A\#)(5|m||6|m6|7|m7|\+7|m\+7|sus2|sus4|9|m9)\b
    такая конструкция не ловит A#. Или может я неправильно экранирую?
    Ну можно сделать вместо
    (A|Ab|A\#)
    вот так
    (A)(\#|b||)
    но сути это особо не изменит, хотя покороче, согласен)
     
  9. Black Raven

    Black Raven Активный пользователь

    С нами с:
    8 июн 2009
    Сообщения:
    25
    Симпатии:
    0
    (A#|A|Ab)

    а вообще уменьшение первого паттерна в 3 раза помоему не просто "покороче" :)
     
  10. TheShock

    TheShock Активный пользователь

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    PHP:
    1. <?php
    2. $chords = array ('C5', 'D#m6', 't123', 'Gb7sus2', 'abc', 'php');
    3. $regexp = '/([A-G][b#]?)(5|m|M|6|m6|7|m7|\+7|m\+7|sus2|sus4|9|m9)?/';
    4. foreach ($chords as $ch) {
    5.     echo preg_match($regexp, $ch) ? 'true ' : 'false';
    6.     echo " - $ch \n";
    7. }
    8. ?>
    Результат:
    Код (Text):
    1. true  - C5
    2. true  - D#m6
    3. false - t123
    4. true  - Gb7sus2
    5. false - abc
    6. false - php
     
  11. PCSpeaker

    PCSpeaker Активный пользователь

    С нами с:
    26 дек 2007
    Сообщения:
    84
    Симпатии:
    0
    TheShock, огромное спасибо, работает как надо.
     
  12. PCSpeaker

    PCSpeaker Активный пользователь

    С нами с:
    26 дек 2007
    Сообщения:
    84
    Симпатии:
    0
    Появилась тут проблемка с этим вариантом
    К примеру вариант A7sdasdasd будет подходить под шаблон, так как preg_match, насколько я понимаю, ищет шаблон внутри строки, а мне нужно чтобы строка целиком совпадала с этим шаблоном. Как это можно реализовать?
     
  13. TheShock

    TheShock Активный пользователь

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    может, \b, или ^(regexp)$ ?
     
  14. PCSpeaker

    PCSpeaker Активный пользователь

    С нами с:
    26 дек 2007
    Сообщения:
    84
    Симпатии:
    0
    Спасибо, помогло.
    Кстати решил не разделять строки на аккордные и неаккордные, так как слова "I am" почти не встречаются, а вот всякие разные символы и комментарии на строках с аккордами встречаются почти в каждых аккордах и поэтому перестают подсвечиваться.