如何在两个标签之间捕获字符串

3

我正在编写一个书签脚本来提高我的工作流程。我的工作的一部分是获取正确的信息放入电子邮件中。我喜欢JavaScript和jQuery,因此我正在尝试使用这个库来简化我的工作。

我针对的网站有特别奇怪的标记语言。我需要捕获匹配标签后的文本,并在下一个标签之前。这一切,奇怪的是,都在一个P标记内。我不知道为什么网站的开发人员决定使用标签,我也无法修改标记,所以这不是一个选项。我已经搜索了整个网络,但还没有找到适合我特定情况的工作方法。

我创建了一个jsFiddle,演示了我想要使用相同标记和CSS来做的事情。我可以轻松访问标签,我已经使用了几种不同的方法来达到这个目的(在fiddle中注释掉了),但我仍然无法正确“捕获”两个标签之间的文本。这段文字最终将被放置到警报中,以便我快速复制它。我尝试过使用.nextUntil,但没有成功。

基本上,它应该是这样的:

<label>item 1</label> Content to capture
<br><br>
<label>item 2</label> Don't capture this...

我担心我的尝试失败的原因是因为(我认为)nextUntil() 会尝试使用初始选择器查找下一个对象,所以它会查找下一个标签,而不是中间的文本。 我已经尝试过使用 $('selector').parent().nextUntil('label'),但也没有成功。
这是一个有效的示例:

$(document).ready(function(){
  //$('p label:eq(0)')afterUntil('<br>').css('color', 'red');
  //$('p').find($('label:contains("item 1")')).nextUntil("<label>").css('color', 'red');
  $('p label:contains("item 1")').parent().nextUntil('label').css('color','red');
});
label {
  display:inline-block;    
  width:25%;
  font-weight:bold;
}
p {
  font-family:arial;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<p>
  <label>item 1</label> Capture me!<br><br>
  <label>item 2</label> Don't capture me
</p>

(fiddle: http://jsfiddle.net/1c2LpzrL/1/)


1
欢迎来到SO!请在fiddle中发布您的代码并且在问题中也贴出。如果由于某种原因jsfiddle无法使用或者您的代码消失了,那么您的问题就会失去宝贵的资源。 - Kyll
6个回答

2
你可以将 <p> 标签内的 HTML 视为字符串,然后获取在 </label> 和第一个 <br> 之间的子字符串。
var totalText = $("p").html();
//determine start-pos and end-pos of desired substring, and then get it
var startPos = totalText.indexOf("</label>") + "</label>".length;
var endPos = totalText.indexOf("<br");
var targetText = totalText.substring(startPos,endPos).trim();

(fiddle: http://jsfiddle.net/3uw8ux9t/3/)

  1. startPos函数找到第一个"</label>"的位置,并加上"</label>"的长度。
  2. endPos函数找到第一个"<br"的位置(我省略了关闭的>因为它可以有两种拼写方式:<br /><br>)。
  3. targetText函数最终从startPosendPos中提取子字符串。
    .trim()函数可删除新字符串开头和结尾的任何空格)

    • console.log(targetText)输出:

    Capture me!


更新:

根据您的评论,我重写了脚本以满足您的要求:

$(document).ready(function(){
  function getUnenclosedText(selector,pointer,tag) {
    var str = $(selector).html();
    //determine start-pos and end-pos
    var startPos = str.indexOf(pointer+"</"+tag+">") + (pointer+"</"+tag+">").length;
    var endPos = str.indexOf("<"+tag,startPos);
    //if there are line-breaks, reset end-pos
    if (str.indexOf("<br",startPos)<endPos || endPos==-1) {
      endPos = str.indexOf("<br",startPos);
    }
    //return substring
    if (endPos==-1) {return str.substring(startPos).trim();} //if it was the last text in the container
    else {return str.substring(startPos,endPos).trim();}
  }
  
  console.log(getUnenclosedText("p","item 1","label")); //(selector,pointer,pointerTag)
  alert('Item 1: '+getUnenclosedText("p","item 1","label") +'\n'+ 'Item 3: '+getUnenclosedText("p","item 3","label"));
});
p {
  font-family:arial;
}

label {
  display:inline-block;    
  width:25%;
  font-weight:bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<p>
  <label>item 1</label> Capture me!
  <br /><br />
  <label>item 2</label> Don't capture me
  <label>item 3</label> capture me as well
  <br /><br />
  <label>item 4</label> Don't capture me either
</p>

(fiddle: http://jsfiddle.net/3uw8ux9t/9/)

我尽可能使其可扩展,使用变量表示参数,因此脚本不再局限于<p><label>

  • 现在,每次您想要提取一段文本时,都必须调用函数getUnenclosedText(selector,pointer,tag)。三个参数使该函数具有可扩展性,因此您可以在各种元素上使用它,而不仅仅是在<p>中的<label>:
    • "selector"指定要对哪些容器元素执行该函数。因此,如果您例如有多个具有不同ID的<p>标签,则可以使用其jQuery选择器访问特定的<p>标签(例如"p#someid")。
    • "pointer"指定要提取未封闭文本的位置之后的内容(例如"item 1""item 2")。
    • "tag"指定封闭指针的标记类型(例如"label""span")。

如果您有任何问题,请在评论中询问,我会回答您或根据需要更新此答案,但我认为您可以在互联网上找到大部分所需内容。
阅读此处关于如何使用indexOf(),您将理解代码中最困难的部分。


你的方法似乎是最好的,对我来说是最有意义的,并且具有潜在的可扩展性。我需要能够在<P>标签中找到多个不同的关键字并将其作为字符串检索出来,以便可以在警报中提供服务。您可以在此分支的Fiddle中看到,如果我尝试将其更改为“项目2”,它实际上会返回“项目2”而不是旁边的内容。对于“item 1”完全正常工作。我对您的代码进行了一些小的编辑,以使其不会在控制台中返回标记。 Fiddle: http://jsfiddle.net/3uw8ux9t/4/ - Benderhune
我认为你的代码引起问题的原因是endPos是第一个"<br"的实例,而不是匹配文本中第一个"<br"的实例。如果它只找到第一个"<br",它将永远无法提取多个文本字符串。 - Benderhune
@Benderhune - 你说得完全正确,那就是它的工作原理。我稍微重写了一下我的代码(请参见更新),以便更精确地提取文本。 - myfunkyside
1
@myfunkside 太棒了!这个完美地运行了,非常感谢您的帮助。我想点赞,但我还没有足够的SO声望。 - Benderhune
@Benderhune 我会耐心等待的 :) 很高兴能帮忙。 - myfunkyside

2
如果问题是找到标签之间的文本/HTML,您可以将原始HTML文本按标签拆分为数组。
var items = paragraphNode.innerHTML.split(/<label>[\s\S]*?<\/label>/g);

这种解决方案的好处在于正则表达式可以轻松更改以支持其他标签或更复杂的结构。
演示在这里: http://jsfiddle.net/x2u8ysx2/

1

$('p label:contains("item 1")').prop('nextSibling')会选择标签后的文本节点。

如果您想使用CSS样式来设置它,那么您需要使用jQuery将该文本包装在一个标签中,并将CSS颜色设置为红色。或者将<p>标签上的内容设置为红色,并将该标签的颜色设置回其原始颜色。

还要记住,.nextSibling返回的是文本节点而不是jQuery对象。


0
你不能仅使用jQuery获取特定文本,因为它只处理元素。你想要的文本在元素之间,父元素包含比你想要的更多的文本。
你可以从该标签的DOM节点开始到下一个标签,并从它们获取文本内容。
在你的示例中,标签之间有两个文本节点和两个
元素,因此你需要决定你想从
元素中获取什么。在这个例子中,我已经将它们翻译成了文本中的换行符。
var e = $('p label:eq(0)')[0].nextSibling;
var s = '';
while (e.tagName != 'LABEL') {
    if (e.tagName == 'BR') {
        s += '\n';
    } else {
        s += e.nodeValue;
    }
    e = e.nextSibling;
}
console.log(s);

示例:http://jsfiddle.net/Guffa/1c2LpzrL/3/


从技术上讲,.prop('nextSibling') 可以让您选择文本节点。 - arjabbar
@arjabbar:是的,从技术上讲,您甚至可以使用jQuery来提取节点中的某些内容,但这完全不实用。 - Guffa

0

jsfiddle演示

function captureStr(p, itm) {
    if(p.find('label').length > 0 && p.find('label:eq(0)').text().indexOf(itm) >= 0)
        return p.html().split("<br>")[0].split("</label>")[1].trim();
}

测试:

console.log(captureStr($('p'), "item 1"));

抓我吧!
如果你有很多这样的结构,那么你可以循环遍历并为每个调用函数。

0
假设结构与您提供的结构不会有太大变化,以下代码将根据下一个非空同级节点输出节点到控制台。我认为这应该适用于任意数量段落标签中的许多标签。这里有一个可以工作的JSFiddle (http://jsfiddle.net/RVAProgrammer/jsqxfgxe/)
console.log($('p').contents().filter(function () {
    var isTextNode = this.nodeType === Node.TEXT_NODE

    if (isTextNode) {
       if ($(this)[0].nextElementSibling === null) {
          return false;
       }
      return true;
    }

    return false;
}).text());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接