首页 文章

在部分html字符串中查找匹配的结束标记

提问于
浏览
1

我有一个部分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>

(位置编号是特定标记开头的 <
给定位置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>

我've tried several methods so far. First, I'已使用 strpos 找到匹配的结束标记,然后查看起始点和结束标记之间是否有另一个开始标记 . 如果找到,我会查找下一个匹配的结束标记 . 相当凌乱 .

然后我尝试搜索下一个匹配的开始标记(前面带有“<”的标记名称),然后检查它们之间是否有结束标记 . 也很乱 .

最后,我从指定位置的标记开始,构建了一个开始和结束标记的列表(堆栈) - 在开始标记上推送标记名称,并在匹配的结束标记上弹出标记名称(如果匹配),直到堆栈有一个项目与起始标记匹配 . 每次操作时,我都会跟踪位置,以便最终得到起始位置(开始标记中>后面的字符)和结束位置(结束标记的<字符前面的字符) .

它忽略了不匹配的结束标记 . 例如,如果有一个打开 p 标记,然后是一个打开 b 标记,然后它找到没有结束 b 标记的结束 /p 标记,它会从列表中删除 b 标记 . 同样,如果它找到一个不在堆栈中的结束标记,它会忽略它 . 例:

<p><b>some text</p></b>

<b></b> 都被忽略 .

最后一种方法似乎是最好的想法,但我想知道是否有其他人有更好的主意 .

我不是在找人写代码 . 我能做到 . 我正在寻找一个概念/想法 . 如果我上面的最后一个想法是最好的,我也很乐意听到 .

如果它在左侧场地出来的话,我也希望听到这一点,但如果你能解释原因并提供更好,更理智的方式,我将不胜感激 .

我想我正在寻找一个“现实”检查,以确保我不会使解决方案复杂化 .

提前致谢!

斯隆

2 回答

  • 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;
      }
    }
    

    我没有编译那段代码,但哲学就在这里 .

    您只能通过字符串搜索字符串搜索字符<和>(TODO:管理\“)每次找到<时都会增加一个计数器,并在每次找到>时减少它 . 您保存最后的<和>位置提取有趣的部分 .

  • 0

    我通过编写一个伪解析器解决了我的问题 . 这是非常基本的,从指定位置的标签开始 . 它逐步执行字符串,识别每个标记和结束标记 . 它还会监视自动关闭标签(即 . ) . 对于每个开始标记,它将其推送到堆栈,对于每个结束标记,如果它与最后一个开始标记匹配,则将其从堆栈中弹出 . 当它从堆栈中弹出最后一个匹配的标记时,它找到了起始标记的匹配结束标记 .

    在工作时,它会跟踪开始标记的结束和匹配结束标记的开始 . 这允许它知道起始标签包含的字符串的起始位置和结束位置 . 我添加了一些“智能”来检测和处理未匹配的标签,但总的来说,它就像描述的一样简单 .

    我正在使用它来解析网页上的信息,找到并捕获特定数据 . 例如,我用它将数据表转换为数据库记录,作为项目的一部分,将手工输入的html表转换为数据库表记录 . 它似乎相当快,解析了12列的超过10k的记录,并在不到0.1秒的时间内将数据插入表中 .

    我选择这种方法而不是使用完整的html或xml解析器,因为在许多情况下,起始位置是基于另一个元素之后的元素而不是能够使用css选择器 . 对于所涉及的特定html,使用css选择器确定起始位置会更加困难,但是使用知道起点的strpos很容易跳过一些与所需元素的选择器匹配的html .

相关问题