1. A777MP17816.03.2025 в 19:24от
Загрузка...

Регулярные выражения для Delphi / C# и других.

Тема в разделе "С/С++/Pascal/Delphi", создана пользователем DedMoroz, 15.01.2015.

  1. DedMoroz

    DedMoroz

    Статус:
    Оффлайн
    Регистрация:
    02.08.12
    Сообщения:
    97
    Репутация:
    58 +/-
    Справка для тех, кому нужно легко парсить текст, вытаскивать данные из больших объемов текста и делать это легко и быстро. C#, Delphi и др.

    Пишите в ответах примеры текста, где вам нужно использовать регулярное выражение, какие данные нужно получить - я помогу вам разобраться, соберем базу примеров и дальше эта тема будет как справочник.

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

    Что такое регулярные выражение? Обойдемся без терминов, это то - что упростит жизнь тебе, сделает её проще и интереснее, и вникнув один раз ты уже никогда не сможешь отказаться от них. Регулярные выражения есть почти во всех языках программирования и каждый раз они неоценимо полезны. Регулярные выражения настолько полезны, что они даже есть в меню разработчика Chrome и блокноте Notepad++.

    Для удобства я буду приводить примеры, которые будут близки к тематике YouHack.

    Допустим, у нас есть список логинов и паролей разделенных символов и мы хотели бы быстро их разделять. Для этого можно использовать много разных приёмов, но самый простой - регулярные выражния. Покажу на примере:

    Код:
    
    
    Как их разбить при помощи регулярных выражений:

    C#
    Код:
                        using System.Text.RegularExpressions;
    
                        MatchCollection matches = Regex.Matches("abcdf:12345", "(?<login>.*?):(?<password>.*?)$");
                        string       Login = matches[0].Groups["login"].Value;
                        string Password = matches[0].Groups["password"].Value;
    
    (?<login>.*?):(?<password>.*?)$ - познакомься, это регулярное выражение. Буквально это означает: прочитать первый блок, который содержит любые символы .*? и назвать этот блок ?<login>, далее следует символ : и за ним следующий блок, который похож на первый, но его мы обозначим как password. Символ $ означает конец строки.

    Как ты заметил у нас массив данных типа MatchCollection - matches[0] где 0 - порядковый номер найденного результата применения регулярного выражения. Если в нашем списке будет два повторения этого шаблона:

    Код:
    abcd:1234
    zxcv:6789
    То первая строка будет иметь индекс matches[0], а вторая matches[1] и ты сможешь обработать их так:

    Код:
          
         foreach (Match match in matches)
         {
                 string Login = match.Groups["login"].Value;
                 string Password = match.Groups["password"].Value;
         }
    
    Всё тоже самое, но без имен:

    Код:
                       using System.Text.RegularExpressions;
    
                        MatchCollection matches = Regex.Matches("abcdf:12345", "(.*?):(.*?)$");
    
                        foreach (Match match in matches)
                        {
                             foreach (Group group in match.Groups)
                             {
                                     string ParamValue = group.Value;
    
                                     MessageBox.Show(ParamValue);
                             }
                        }
    
    Этот пример выведет 3 сообщения, так как мы сперва перебираем результаты поиска всего выражения Match, а потом каждый блок Group - блоки идут в скобках. Мы получим результат:

    abcdf:12345
    abcdf
    12345

    Да, ты всё правильно понял, каждый Match у нас содержит группу в которой 0 элемент содержит весь блок, который задан в регулярном выражение, а потом каждый последующий элемент группы будет содержать то, что мы указали в скобках.


    Вот тебе несколько вариант регулярных выражений и примеры, где их можно применить:

    У нас есть текст: <a href="http://somelink.net/?userid=123423">This is my link Number 1</a>

    ([A-z0-9]+) - все буквы от A заглавной до z маленькой и все числа.
    Код:
    href="([A-z0-9]+)
    
    Результат: 
    href="http
    http
    
    (\d+) - любое число
    Код:
    (\d+)
    
    Результат: 
    123423
    123423
    
    (\w+) - любое слово
    Код:
    This is my link (\w+)
    
    Результат:
    This is my link Number
    Number
    
    (.*?) - любые символы
    Код:
    href="(.*?)"
    
    Результат:
    href="http://somelink.net/?userid=123423"
    http://somelink.net/?userid=123423
    
    Рассмотрим вариант применения блоков вместе:
    Код:
    <a href="(.*?)">This is my link (\w+) (\d+)</a>
    
    Результат:
    Все выражение: <a href="http://somelink.net/?userid=123423">This is my link Number 1</a>
    Блок (.*?) http://somelink.net/?userid=123423
    Блок (\w+) Number
    Блок (\d+) 1
    

    Теперь очень важное замечание, плюс в конце выражения означает - что элементов может быть несколько, если нужно задать точное количество символов используйте {4} например (\d{4}) - в блоке 4 символа:

    Пример текста: <input type="text" name="elementsToSend[]" value="00146700" note="element:block">

    Код:
    value="00(\d{4})
    
    Результат:
    Найденный результат по выражению value="001467
    Блок (\d{4}) даст результат 1467
    
    Обозначайте конец регулярного выражения, например link="(.*?)" ковычкой или специальным символом, например конец строки (\w+)$, начало строки ^. Допустим у нас есть несколько строк с данными:

    Hi 123 block
    Hi 234 block

    Регулярное выражение будет: ^Hi (\d{3}) block$
    Результат для первой строки:
    ^Hi (\d{3}) block$ -----> Hi 123 block
    (\d{3}) -----> 123


    Это далеко не все примеры, которые можно разобрать, пишите ниже что вам нужно вытащить из текста, будем разбираться.

    Что касается Delphi, то тут всё аналогично, регулярные выражения почти идентичны и достаточно один раз научиться с ними работать - это останется на всю жизнь и вы будете их читать как обычный текст, требуется практика. Тут поможет аналогия с фильмом Матрица, кто смотрел поймут, одни на экране видят вертикальные символы, а другие - картинку мира. У нас примерно так же с регулярными выражениями.

    Как использовать регулярные выражения в Delphi - прикреплю модуль для работы с регуляркой. В последних версиях Delphi такой модуль уже есть.

    Скачать модуль для Delphi старых версий http://rghost.ru/60355240

    Можно просто кинуть в каталог с проектом, используем:

    Код:
    var regex: TRegExpr;
    TextToParse: String;
    begin
         TextToParse:='{"code":"ae30f8e7d7e32e9d8f8324"}';
         regex:=TRegExpr.Create;
         regex.Expression:='code":"(.*?)"';
         regex.Exec(TextToParse);
    end;
    
    Результат:

    regex.Match[0] содержит code":"ae30f8e7d7e32e9d8f8324"
    regex.Match[1] содержит ae30f8e7d7e32e9d8f8324

    Тот же пример в последних версия Delphi.

    Код:
    uses RegularExpressions;
    
    var
       regex: TRegEx;
       TextToParse: String;
       match   : TMatch;
       group   : TGroup;
    begin
         TextToParse:='{"code":"123"}{"code":"456"}';
         regex:=TRegEx.Create('code":"(.*?)"',[roIgnoreCase,roMultiline]);
         match := regex.Match(TextToParse);
         while match.Success do
          begin
            ShowMessage(match.Groups[1].Value);
            match := match.NextMatch;
          end;
    
    Результат первое сообщение 123, второе 456


    На закуску, для тех кто пользуется Notepad++, умеет или не умеет программировать:

    К примеру у нас есть текст:

    Код:
    1: login1@mail.ru 123123 (some description)
    2: login1@mail.ru 123123 (some description)
    3: login1@mail.ru 123123 (some description)
    4: login1@mail.ru 123123 (some description)
    5: login1@mail.ru 123123 (some description)
    
    Надо получить формат email:password с описанием на новой строчке снизу с отступом

    Нажимаем Ctrl+F и переключаемся на вкладку Replace (Замена)

    Делаем как на картинке:

    [​IMG]

    Получаем:

    Код:
    login1@mail.ru:123123
        some description
    login1@mail.ru:123123
        some description
    login1@mail.ru:123123
        some description
    login1@mail.ru:123123
        some description
    login1@mail.ru:123123
        some description
    

    Думаю у вас остались вопросы - задавайте в формате:

    1. Где хотите использовать регулярное выражение (Delphi, C#)
    2. Какие данные имеете (пример)
    3. Что хотите получить
    [/hide]
     
    Последнее редактирование: 20.01.2015
  2. Soviet

    Soviet

    Статус:
    Оффлайн
    Регистрация:
    19.10.14
    Сообщения:
    107
    Репутация:
    13 +/-
    Спасибо огромное за старание ТС, давно искал что то по этой теме, но не всегда понятно да и чистый текст, добавил в закладки)
     
  3. DedMoroz

    DedMoroz

    Статус:
    Оффлайн
    Регистрация:
    02.08.12
    Сообщения:
    97
    Репутация:
    58 +/-
    Ты главное вопросы задавай и примеры скидывай, где есть потребность использовать, регулярка требует постоянной практики.
     
  4. Soviet

    Soviet

    Статус:
    Оффлайн
    Регистрация:
    19.10.14
    Сообщения:
    107
    Репутация:
    13 +/-
    Вот мне бы регулярку написать, что бы парсила по 2 значения в одну строку по таким значениям:
    с 'title="View Account Activity for&nbsp;' {тут переменный текст который нужно парсить} по '&nbsp;' {тут переменный текст который нужно парсить} по '"'
    Как правильно реализовать хз, нуждаюсь в помощи.
    делфи
     
    Последнее редактирование: 15.01.2015
  5. DedMoroz

    DedMoroz

    Статус:
    Оффлайн
    Регистрация:
    02.08.12
    Сообщения:
    97
    Репутация:
    58 +/-

    Не знаю какая у тебя версия Delphi. Если в Delphi у тебя есть RegularExpressions стандартный модуль, то

    Код:
    uses RegularExpressions;
    Код:
    var
        regex: TRegEx;
        str:string;
        match:TMatch;
    begin
    
         str:='title="View Account Activity for&nbsp;123&nbsp;456"';
         regex:=TRegEx.Create('title="View Account Activity for&nbsp;(.*?)&nbsp;(.*?)"');
         match:=regex.Match(str);
         if match.Success then
            showmessage('Найдено: '+match.Groups[0].Value+#13+'В скобках 1: '+match.Groups[1].Value+#13+'В скобках 2: '+match.Groups[2].Value);
    end;
     
    Последнее редактирование: 20.01.2015
  6. Soviet

    Soviet

    Статус:
    Оффлайн
    Регистрация:
    19.10.14
    Сообщения:
    107
    Репутация:
    13 +/-
    Спасибо, работает.Очень полезная тема.
     
  7. Soviet

    Soviet

    Статус:
    Оффлайн
    Регистрация:
    19.10.14
    Сообщения:
    107
    Репутация:
    13 +/-
    Я вот что еще хотел спросить,можно написать такую регулярку что бы начало парсинга бралось не со всего стринг листа а поочередно всех строк, то есть в каждой строке, я сделал циклом, можно как то по проще?
     
  8. DedMoroz

    DedMoroz

    Статус:
    Оффлайн
    Регистрация:
    02.08.12
    Сообщения:
    97
    Репутация:
    58 +/-

    Лови

    Результат - покажет 5 сообщений:
    TJFD-DDFR4-UI32
    TJFD-EDSF2-UI32
    TJFD-BFGS2-UI32
    TJFD-SDDS3-UI32
    TJFD-SDFZX-UI32


    Для работы многострочным текстом необходимо добавить опцию roMultiline Разберем саму регулярку.

    Регулярка: ^.*?key: (.*?)<.*$

    ^ - начало строки
    .*? - любые символы
    key: - слово в тексте с двоеточием, причем после двоеточия пробел
    (.*?) - любые символы, но в данном случае скобки указывают на то, что эти символы мы хотим получить в результате выполнения регулярное выражения (группу с индексом [1] - match.Groups[1].Value)
    < - символ в тексте, указываем, что предыдущий блок нужно ограничить до этого символа, в тексте это тег </a>
    .*? - любые символы
    $ - конец строки

    Обратить внимание надо на то, что символ $ не будет работать без опции roMultiline.

    Результат поиска с индексом группы 0 будет содержать всю найденную строку:
    match.Groups[0].Value = '<a href="http://steampowered.com" target="_blank">Activate steam key: TJFD-DDFR4-UI32</a>';



    Аналогичный пример на С#

    Обратите внимание, что как и в примере на Delphi необходимо указывать опцию Multiline для работы символа $, указывающего на конец строки. Результат так же отражается в группах, где группа с индексом 0 - содержит всю найденную строку, а группа с индексом 1 - данные, которые в регулярном выражение указаны в скобках. Различий в самом регулярном выражении нет.
     
    Последнее редактирование: 20.01.2015
  9. Soviet

    Soviet

    Статус:
    Оффлайн
    Регистрация:
    19.10.14
    Сообщения:
    107
    Репутация:
    13 +/-
    Спасибо огромное, так доступно и понятно объясняешь)
     
  10. DedMoroz

    DedMoroz

    Статус:
    Оффлайн
    Регистрация:
    02.08.12
    Сообщения:
    97
    Репутация:
    58 +/-
    -удалено
     
    Последнее редактирование: 20.01.2015
  11. Soviet

    Soviet

    Статус:
    Оффлайн
    Регистрация:
    19.10.14
    Сообщения:
    107
    Репутация:
    13 +/-
    Бро помоги написать регулярку на шарпе, я накидал но она не пашет:
     
  12. Payback

    Payback

    Статус:
    Оффлайн
    Регистрация:
    20.08.13
    Сообщения:
    111
    Репутация:
    55 +/-


    Помоги, пожалуйста