[Delphi]Парсинг значений

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by Klubni4ka, 4 May 2011.

  1. Klubni4ka

    Klubni4ka New Member

    Joined:
    10 Mar 2011
    Messages:
    8
    Likes Received:
    0
    Reputations:
    0
    Столкнулся с задачей.
    Следует спарсить данные на странице, данные находятся между тегами <teg1> и <teg2>.
    Загвоздка состоит в том, что таких данных на странице достаточно много...

    Подскажите как спарсить все необходиые данные между тегами <teg1> и <teg2>.

    Движусь так...
    Код:
    Code:
     
      s:=IdHTTP1.Get('http://sait.ru/catalog);
      s:=copy(s,pos('<teg1>',s)+length('<teg1>'),pos('<teg2>',s)-length('<teg2>'));
    
    Но ничего не выходит...
     
  2. xophet

    xophet Member

    Joined:
    16 Apr 2011
    Messages:
    617
    Likes Received:
    49
    Reputations:
    5
    Code:
    s:=IdHTTP1.Get('http://sait.ru/catalog);
    while (pos('<teg1>',s)>0) and (pos('<teg2>',s)>0) do
    begin
        ss:=copy(s,pos('<teg1>',s)+length('<teg1>'),pos('<teg2>',s)-length('<teg2>')-1);
        showmessage(ss); //тут сделаешь с этим значением то, что нужно
        delete(s,1,pos('<teg2>',s)+length('<teg2>')-1);
    end;
    
    а вкратце: кроме copy надо еще и удалять те теги, которые не нужны
    т.е. <teg1>a<teg2><teg1>b<teg2><teg1>c<teg2><teg1>d<teg2>
    a скопировал,
    удалил <teg1>a<teg2>
    b скопировал,
    удалил <teg1>b<teg2> и т.д.
     
    #2 xophet, 4 May 2011
    Last edited: 4 May 2011
  3. kolored

    kolored New Member

    Joined:
    16 Sep 2009
    Messages:
    18
    Likes Received:
    1
    Reputations:
    0
    Пользуюсь такой функцией:
    T_ - открывающий тег
    ForS - исходный текст
    _T - закрывающий текст

    Ищет первое вхождение
    Code:
    function Pars(T_, ForS, _T: string): string;
    var
      a, b: integer;
    begin
      Result := '';
      if (T_ = '') or (ForS = '') or (_T = '') then  Exit;
      a := Pos(T_, ForS);
      if a = 0 then    Exit
      else  a := a + Length(T_);
    
      ForS := Copy(ForS, a, Length(ForS) - a + 1);
      b := Pos(_T, ForS);
      if b > 0 then Result := Copy(ForS, 1, b - 1);
    end;
     
  4. waik

    waik Elder - Старейшина

    Joined:
    2 Nov 2008
    Messages:
    404
    Likes Received:
    163
    Reputations:
    12
    Code:
    function Pars(T_, ForS, _T: string): string;
    var
      a, b: integer;
    begin
      Result := '';
      if (T_ = '') or (ForS = '') or (_T = '') then Exit;
      a := Pos(T_, ForS);
      if a = 0 then Exit
      else a := a + Length(T_);
    
      ForS := Copy(ForS, a, Length(ForS) - a + 1);
      b := Pos(_T, ForS);
      if b > 0 then Result := Copy(ForS, 1, b - 1);
    end;
    
    s:=IdHTTP1.Get('http://sait.ru/catalog);
    
    t:=Pars ( '<teg1>', s, '<teg3>' );
     
  5. xophet

    xophet Member

    Joined:
    16 Apr 2011
    Messages:
    617
    Likes Received:
    49
    Reputations:
    5
    Wait, вы не читаете первый пост, а жаль. Сам пользуюсь этой функцией, переделал в ней:
    1) при пустом T_ или _T парсится от начала или до конца соответственно;
    2) ввел CaseSensitive:boolean, для того, чтобы можно было искать не заботясь о регистре букв.
    Но ТС интересно было именно как распарсить все значения со страницы, а не только 1е (которое выдавале его copy(....) и выдаст Pars(....))

    хотя как вариант можно переделать мой цикл под использование Pars(...) но смысла это не изменит

    если кому интересно вот переделанная ф-ия Pars:
    Code:
    function Pars(T_, ForS, _T: string; CaseSensitive:Boolean): string;
    var
      a, b: integer;
    begin
      Result := '';
      if (ForS = '') then
        Exit;
        if T_='' then a:=1
        else
        if CaseSensitive then a := Pos(T_, ForS)
        else a := Pos(UpperCase(T_), UpperCase(ForS));
        if a = 0 then
          Exit
        else
          a := a + Length(T_);
      ForS := Copy(ForS, a, Length(ForS) - a + 1);
      if _T='' then b:=Length(forS)+1
      else
       if CaseSensitive then b := Pos(_T, ForS)
        else b := Pos(UpperCase(_T), UpperCase(ForS));
      if b > 0 then
        Result := Copy(ForS, 1, b - 1);
    end;
    
    Как видно, даже при CaseSensitive:=true; результатом будет строка с символами в том же регистре, что и в оригинале.
     
    #5 xophet, 6 May 2011
    Last edited: 6 May 2011
  6. GhostOnline

    GhostOnline Active Member

    Joined:
    20 Dec 2008
    Messages:
    723
    Likes Received:
    110
    Reputations:
    22
    Я тут один про PosEx знаю?
    Вот функция, примерно такой же объем кода но парсит все вхождения, возвращает TStrings, не забываем проверять на nil и освобождать
    Code:
    function Parse(const tag1, tag2, source: string): TStrings;
    var
     p, p2, len: Integer;
    begin
     Result := nil;
     p := Pos(tag1, source);
     len := Length(tag1);
     p2 := PosEx(tag2, source, p + len + 1);
     if (p = 0) or (p2 = 0) then
        Exit;
     Result := TStringList.Create;
     while (p > 0) and (p2 > 0) do
      begin
         if p2 > p then
           Result.Add(Copy(source, p + len, p2 - p - len));
         p := PosEx(tag1, source, p2);
         p2 := PosEx(tag2, source, p + len + 1);
      end;
    end;
    Пример использования:
    Code:
    var
      strings: TStrings;
    begin
     strings := Parse('<a href="', '"', Memo1.Lines.Text);
     if strings <> nil then
      begin
        Memo2.Lines.AddStrings(strings);
        strings.Free;
      end;
    end;
    PS А вообще, такие вещи обычно решаются с помощью регулярок
     
    #6 GhostOnline, 6 May 2011
    Last edited: 6 May 2011
  7. xophet

    xophet Member

    Joined:
    16 Apr 2011
    Messages:
    617
    Likes Received:
    49
    Reputations:
    5
    О, спасибо! Похоже что из всех присутствующих только ты :)))
    P.S. До регулярок дорасти еще надобно, пока и без них головняка хватает.
     
  8. kakeolala

    kakeolala Banned

    Joined:
    13 Jul 2010
    Messages:
    118
    Likes Received:
    2
    Reputations:
    0
    ну регулярками куда удобнее.
    Я раньше тоже через Pos, Copy работал а регулярок "бояслся" думал что сложно

    А вот маска регулярки под вашу задачу: <teg1>(.*)<teg2>
     
  9. xophet

    xophet Member

    Joined:
    16 Apr 2011
    Messages:
    617
    Likes Received:
    49
    Reputations:
    5
    Kakeola, а где подробнее можно почитать по поводу регулярок? а то я как раз тож боюсь, и нигде на глаза толковой литературы по этому поводу не попадалось
     
  10. kakeolala

    kakeolala Banned

    Joined:
    13 Jul 2010
    Messages:
    118
    Likes Received:
    2
    Reputations:
    0
    вот эта ссылка хорошая - http://forum.vingrad.ru/forum/act-ST/f-84/t-213075.html я ее читал.

    А вообще будут вопросы - спрашивай на винграде ибо тут тебе скажут как ломануть))))
    А там специалисты широкого профиля и улучшенно подскажут как и что и какие ссылки почитать
     
  11. totenkopf

    totenkopf Elder - Старейшина

    Joined:
    19 Jul 2010
    Messages:
    91
    Likes Received:
    63
    Reputations:
    19
    А если без регулярок то логика такая:

    Псевдокод:

    Измеряем длину <tag1>

    Метка1:

    Находим позицию <tag1>
    К позиции <tag1> прибавляем длину <tag1> получаем указатель на нужные данные X
    Находим позицию <tag2> и заносим на ее место байт 0
    считываем данные по указателю X

    Повторяем весь поиск начиная с позиции <tag2> + 1 (Переход на Метка1) пока любой поиск не вернет ошибку
     
    #11 totenkopf, 12 May 2011
    Last edited: 12 May 2011
  12. kakeolala

    kakeolala Banned

    Joined:
    13 Jul 2010
    Messages:
    118
    Likes Received:
    2
    Reputations:
    0
    Copy(s,Pos('<tag1>,s)++, Pos('<tag2>',s));