使用PHP提取类似HTML的标记
我试图从给定字符串中提取最外层的特殊HTML标记。下面是一个示例字符串:使用PHP提取类似HTML的标记,php,dom,string,Php,Dom,String,我试图从给定字符串中提取最外层的特殊HTML标记。下面是一个示例字符串: sample string with <::Class id="some id\" and more">text with possible other tags inside<::/Class> some more text 带有的示例字符串不是可扩展的解决方案,但它可以工作 $startPos = strpos($string, '<::Class'); $endPos = strrpo
sample string with <::Class id="some id\" and more">text with possible other tags inside<::/Class> some more text
带有的示例字符串不是可扩展的解决方案,但它可以工作
$startPos = strpos($string, '<::Class');
$endPos = strrpos($string, '<::/Class>');
$startPos=strpos($string,您在这里谈论的是制作模板。用于解析模板的Regex非常慢。相反,您的模板读取/处理引擎应该进行字符串解析。这不是非常简单,但也不是非常难。不过,我的建议是使用另一个模板库,而不是重新发明轮子
有一个开源的模板引擎,您可以利用它或从中学习。或者,使用类似的东西。如果性能是一项重要任务,请查看。strpos+strrpos
(哎哟…)
基本上这就是我的想法。类似于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;
}
受保护函数findFirstControl()
{
$pos=strpos($this->mSource,'它不起作用,因为可能有嵌套的标记。我还需要匹配@Marius:为什么不将其更改为XML?另外,如果仔细观察,您会发现第二个方法是,而不是strpos
。该函数在字符串中找到最后一个匹配项。同意“只使用常规XML”,然后解析它?不管它是否是strrpos,因为可能会有两个标签一个接一个。strrpos会返回第二个标签的结尾。我尝试过HTML,但使用DomDocument,我无法仅将标签作为对象获取,而不知道它在字符串中的位置。这正是我的答案试图说明的缺陷即使你想让它工作,效率也会非常低。发明轮子正是这里的目的。我不会把时间浪费在一些商业项目上,但我正在努力学习一些东西,即使这意味着重新发明轮子。这是我自己做事的方式。总是。我更想知道事情是如何工作的而不是盲目地使用某些东西。如果它是开源的,就不是盲目的:)@马吕斯:是的,你可以自由地查看代码并了解它是如何完成的。而且列出的模板引擎中没有一个是商业产品。我想我必须四处看看,并尝试从代码中了解一些东西;]Blitz是用C编写的扩展。我以前也看到过这样做-速度非常快。PHPBB引擎历史上是v从“html注释”开始,设计师通常理解样式在DreamWeaver等应用中发挥了很大的作用,因此有一个优势。OP只是讨论了“最外面的”标记。创建一个非常大的模板的整个映射可能会变得很大。只要所有额外的内存不是问题,这将是一种可行的方法。如果内存是问题,您也可以使用i创建一个标记=>位置的映射n字符串。感谢您为此花费时间。事实上,我已经解决了这个问题。查看您的代码,我可以看到我的方法可能完全相同,只是它没有生成映射,只是替换了第一次出现的内容。好吧,不确定它会有多大用处,因为您已经发布了一个更简洁的解决方案;]
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',
)
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;
}