Извлекайте HTML-подобные теги с помощью PHP - PullRequest
1 голос
/ 17 декабря 2010

Я пытаюсь извлечь OUTERMOST специальные HTML-подобные теги из заданной строки. Вот пример строки:

sample string with <::Class id="some id\" and more">text with possible other tags inside<::/Class> some more text

Мне нужно найти, где в строке начинается тег <:: и где он заканчивается. Проблема в том, что он может содержать вложенные теги внутри. Существует ли простой петлеобразный алгоритм для нахождения ПЕРВОГО вхождения <:: Tag и длины строки до совпадения <:: / Tag>? Я пробовал другой способ, используя вместо этого простой тег HTML и DomDocument, но он не может сказать мне положение тега в строке. Я не могу использовать внешние библиотеки, я просто ищу указатели на то, как это можно решить. Может быть, вы видели алгоритм, который делает именно это - я бы хотел взглянуть на него.

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

Ответы [ 4 ]

1 голос
/ 18 декабря 2010

Так что в основном вот что я придумал. Что-то вроде решения ajreal, но не такое чистое;] Даже не уверен, что оно работает отлично, первоначальное тестирование прошло успешно.

protected function findFirstControl()
{
    $pos = strpos($this->mSource, '<::');

    if ($pos === false)
        return false;

    // get the control name
    $endOfName = false;
    $controlName = '';
    $len = strlen($this->mSource);
    $i = $pos + 3;

    while (!$endOfName && $i < $len)
    {
        $char = $this->mSource[$i];

        if (($char >= 'a' && $char <= 'z') || ($char >= 'A' && $char <= 'Z'))
            $controlName .= $char;
        else
            $endOfName = true;

        $i++;
    }

    if ($controlName == '')
        return false;

    $posOfEnd = strpos($this->mSource, '<::/' . $controlName, $i);
    $posOfStart = strpos($this->mSource, '<::' . $controlName, $i);

    if ($posOfEnd === false)
        return false;

    if ($posOfStart > $pos)
    {
        while ($posOfStart > $pos && $posOfEnd !== false && $posOfStart < $posOfEnd)
        {
            $i = $posOfStart + 1;
            $n = $posOfEnd + 1;
            $posOfStart = strpos($this->mSource, '<::' . $controlName, $i);
            $posOfEnd = strpos($this->mSource, '<::/' . $controlName, $n);
        }
    }

    if ($posOfEnd !== false)
    {
        $ln = $posOfEnd - $pos + strlen($controlName) + 5;
        return array($pos, $ln, $controlName, substr($this->mSource, $pos, $ln));
    }
    else
        return false;
}
1 голос
/ 17 декабря 2010

То, о чем вы здесь говорите, - это создание шаблона.Regex для разбора шаблонов очень медленный.Вместо этого ваш механизм чтения / обработки шаблонов должен выполнять анализ строки.Это не супер-легко, но и не очень сложно.Тем не менее, мой совет - использовать другую библиотеку шаблонов вместо того, чтобы заново изобретать колесо.

В PHPBB есть движок шаблонов с открытым исходным кодом, который вы можете использовать или учиться.Или используйте что-то вроде Smarty .Если производительность важна, взгляните на Blitz .

1 голос
/ 17 декабря 2010

strpos + strrpos (ой ...)

$str   = 'sample string with <::Class id="some id" and more">text with possible <::Strong>other<::/Strong> tags inside<::/Class> some more text';
$tag   = '<::';
$first = strpos($str, $tag);
$last  = strrpos($str, $tag);
$rtn   = array();
$cnt   = 0;
while ($first<$last)
{
  if (!$cnt)
  {
    $rtn[] = substr($str, 0, $first);
  }
  ++$cnt;
  $next = strpos($str, $tag, $first+1);

  if ($next)
  {
    $pos   = strpos($str, '>', $first);
    $rtn[] = substr($str, $first, $pos-$first+1);
    $rtn[] = substr($str, $pos+1, $next-$pos-1);
    $first = $next;
  }
}

С $rtn вы можете делать все, что захотите ... этот код еще не совершенен ...

array (
  0 => 'sample string with ',
  1 => '<::Class id="some id" and more">',
  2 => 'text with possible ',
  3 => '<::Strong>',
  4 => 'other',
  5 => '<::/Strong>',
  6 => ' tags inside',
  7 => '<::/Class> some more text',
)
0 голосов
/ 17 декабря 2010

Не расширяемое решение, но оно работает.

$startPos = strpos($string, '<::Class');
$endPos = strrpos($string, '<::/Class>');

Обратите внимание, что я использовал strrpos для решения проблемы с вложенностью. Кроме того, это даст вам начальную позицию <::/Class>, а не конец.

Почему бы вам просто не использовать обычный XML и DOM? Или просто существующий шаблонизатор, такой как Smarty ?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...