我有一个部分的html字符串,并且给定了开始标记的位置,我希望能够找到匹配的结束标记的位置。我不能使用html解析器(至少我认为我不能)因为html只是一个片段,而不是完整的html。在我正在查看的部分之前或之后可能存在不匹配的标签。该字符串不包含dtd,html,head或body标记。
例如:
<div id='something' class='someclass'>
<h1>Title</h1>
<div><p>some text</p></div>
<div>
<div class='anotherdiv'>
</div>
<div class='yetanother'>
</div>
</div>
</div>
(位置编号是特定标记开头的&lt; )
如果位置为0(从字符串开始),我想获得内容:
<h1>Title</h1>
<div><p>some text</p></div>
<div>
<div class='anotherdiv'>
</div>
<div class='yetanother'>
</div>
</div>
鉴于位置为39(第二行的h1开头),我想获得内容:
Title
给定位置83(第4行div的开头),我想获得内容:
<div class='anotherdiv'>
</div>
<div class='yetanother'>
</div>
到目前为止,我尝试了几种方法。首先,我使用strpos
找到匹配的结束标记,然后查看起始点和结束标记之间是否有另一个开始标记。如果找到,我会查找下一个匹配的结束标记。相当混乱。
然后我尝试搜索下一个匹配的开始标记(前面带有“&lt;”的标记名称),然后检查其间是否有结束标记。也很乱。
最后,我从指定位置开始使用标记,并构建了一个开始和结束标记的列表(堆栈) - 在开始标记上推送标记名称并在匹配时弹出标记名称(如果匹配)关闭标记,直到堆栈有一个项目与起始标记匹配。每次操作时,我都会跟踪位置,以便最终得到起始位置(开始标记中&gt;后面的字符)和结束位置(结束标记的&lt;字符前面的字符)。
它会忽略不匹配的结束标记。例如,如果有一个开头 p 标记,然后是一个开头的 b 标记,那么它会找到结束 / p 标记而没有结束 b 标记,它会从列表中删除 b 标记。同样,如果它找到一个不在堆栈中的结束标记,它会忽略它。例如:
<p><b>some text</p></b>
<b>
和</b>
都会被忽略。
这最后一种方法似乎是最好的想法,但我想知道是否有其他人有更好的想法。
我不是在找人写代码。我能做到。我正在寻找一个概念/想法。如果我上面的最后一个想法是最好的,我也很乐意听到。
如果这是一个坏主意,或者我已经离开了左侧领域,我也希望听到这一点,但如果您能解释为什么和提供更好,更理智的方式,我将不胜感激做到这一点。
我想我正在寻找一个“现实”检查,以确保我不会使解决方案复杂化。
提前致谢!
斯隆
答案 0 :(得分:0)
如何通过char完整浏览你的字符串char:
假设字符串名为s。
int counter = 0;
bool simpleQuote = false;
bool doubleQuote = false;
int lastOpeningBraquetPosition = 0;
int lastClosingBraquetPosition = 0;
for (int i = 0; i < s.size(); i++)
{
char c = s[i];
if (c == "\"")
doubleQuote = !doubleQuote;
if (c == "'")
simpleQuote = !simpleQuote;
if ((c == "<") && (!doubleQuote) && (!simpleQuote))
{
//the car interest us
counter++;
//we save the position of the last "<"
lastOpeningBraquetPosition = i;
}
if ((c == ">") && (!doubleQuote) && (!simpleQuote))
{
//the car interest us
counter--;
if (counter == 0)
{
//TODO : take the interesting part between lastClosingBraquetPosition + 1 and lastOpeningBraquetPosition - 1 with check to ensure to be in the string
return result;
}
//we save the position of the last ">"
lastClosingBraquetPosition = i;
}
}
我没有编译那段代码,但哲学就在这里。
你通过char searhing&lt;和&gt;只在字符串之外(TODO:管理\&#34;) 每次找到&lt;时都会增加一个计数器。并且每次找到&gt;时减少它。你保存最后一个&lt;和&gt;提取有趣部分的位置。
答案 1 :(得分:0)
我通过编写伪解析器解决了我的问题。它非常基本,从指定位置的标签开始。它遍历字符串,识别每个标记和结束标记。它还会监视自动关闭标签(即。)。对于每个开始标记,它将其推送到堆栈,对于每个结束标记,如果它与最后一个开始标记匹配,则将其从堆栈中弹出。当它从堆栈中弹出最后一个匹配的标记时,它找到了起始标记的匹配结束标记。
当它工作时,它会跟踪开始标记的结束和匹配结束标记的开始。这允许它知道起始标签包含的字符串的起始位置和结束位置。我添加了一些&#34; smarts&#34;检测和处理错过匹配的标签,但总的来说,它就像描述一样简单。
我使用它来解析网页上的信息,找到并捕获特定数据。例如,我用它将数据表转换为数据库记录,作为项目的一部分,将手工输入的html表转换为数据库表记录。它似乎相当快,解析了12列的超过10k的记录,并在不到0.1秒的时间内将数据插入表中。
我选择此方法而不是使用完整的html或xml解析器,因为在许多情况下,起始位置是基于另一个元素后面的元素而不是能够使用css选择器。对于所涉及的特定html,使用css选择器确定起始位置会更加困难,但使用知道起点的strpos很容易跳过一些与所需元素的选择器匹配的html。< / p>