如何分割string而不创build格式不正确的HTML标签?

我在做什么

  • 在NodeJS中,我使用MustacheJS创build一个电子邮件模板,使用JSON对象数组中的数据。
  • 模板中的文本/消息可以包含基本的html标签(例如b pa )。
  • 由于空间的限制,我只需要显示消息摘录。 为此,我做了一个字数,然后让我们说20个字(空格检查)我截断string,并追加View more锚点标记。 这将其链接到网站的post页面,其中包含完整的post。 就像是:

嘿,这是一个示例文章<b>message</b> 。 Lorem ipsum dolor sit amit … <a href="someurl">查看更多</a>

问题:

在字数和截断期间,我可能会截断html标签之间的string,因为我只是根据空间计算单词。 就像是:

我正在与你分享链接。 <a style="color:<a style="color:查看更多</a>

现在这将打破HTML。

可能的scheme

  • 在截断string之前,运行一个正则expression式来查找其中的所有html标签。
  • 使用indexOf() (或其他方法)来查找每个标签的起始和结束索引。
  • 在字数后,得到我需要截断它的索引。
  • 现在看到,如果索引与任何标签区域相交。
  • 如果相交,只需将截断索引移动到html标记的开头或结尾。

题:

有一个更好的方法吗。 我不知道我应该search谷歌search条件,以获得帮助。

PS代码是灵活的,我可以改变stream程,如果有一个更好的解决scheme。 另外,我对post的标题不太好。 如果可以,请修改它以反映问题。


编辑:

这是Alex在回答之后提出的。 希望它可以帮助别人:

 /** * Counter: Takes a string and returns words and characters count * @param value * @returns obj: { * 'wordCount': (int), * 'totalChars': (int), * 'charCount': (int), * 'charCountNoSpace': (int) * } */ var counter = function(value){ var regex = /\s+/gi; if (!value.length) { return { wordCount: 0, totalChars: 0, charCount: 0, charCountNoSpace: 0 }; } else { return { wordCount: value.trim().replace(regex, ' ').split(' ').length, totalChars: value.length, charCount: value.trim().length, charCountNoSpace: value.replace(regex, '').length }; } } /** * htmlSubString - Creates excerpt from markup(or even plain text) without creating malformed HTML tags * @param markup {string} - Markup/text to take excerpt out of * @param limit {int} - Total word count of excerpt. Note that only text (not the html tag) counts as a valid word. * @returns {string} - Excerpt */ var htmlSubString = function(markup, limit){ var htmlParser = require("htmlparser2"); var tagCount = 0; var wordCount = 0; var excerpt = ''; function addToExcerpt(type, text, attribs) { if ((wordCount >= limit && tagCount == 0) || (tagCount === 1 && type === 'tagOpen' && wordCount >= limit)) { return false; } else if (wordCount < limit || tagCount) { if (type === 'text') { var wordCountSubString = $scope.counter(text).wordCount; if (wordCountSubString + wordCount > limit && tagCount === 0) { var length = limit - wordCount; var wordList = text.trim().split(' '); for (var i = 0; i < length; i++) { excerpt += ' ' + wordList[i]; wordCount++; } } else { wordCount += wordCountSubString; excerpt += text; } } else if (type === 'tagOpen') { excerpt += '<' + text; for (var prop in attribs) { excerpt += ' ' + prop + '="' + attribs[prop] + '"'; } excerpt += '>'; } else if (type === 'tagClose') { excerpt += '</' + text + '>'; } } return true; } var parser = new htmlParser.Parser({ onopentag: function (name, attribs) { if(wordCount < limit){ ++tagCount; addToExcerpt('tagOpen', name, attribs); } }, ontext: function (text) { if(wordCount < limit){ addToExcerpt('text', text); } }, onclosetag: function (tagName) { if(wordCount < limit || tagCount > 0){ addToExcerpt('tagClose', tagName); --tagCount; } } }); parser.write(markup); parser.end(); return excerpt; } 

用法:

 var wordCountLimit = 20; var markup = "/* some markup/text */"; var excerpt = htmlSubString(markup, wordCountLimit); 

现在,你一定能find一些匹配正则expression式的HTML标签。 这就是说,我不推荐它。 起初,你会很高兴,一切都会正常工作。 那么明天你会发现一个小小的情况。 “别担心!” 你会说,当你修改expression式来解决这个差异。 然后第二天,一个新的调整,一个新的,还有另一个等等,直到你不能再忍受了。

我强烈build议你find一个已经build立的HTMLparsing库。 npm上似乎有不less。 这一个似乎是相当受欢迎的。

PS – 你的问题没有问题。 我希望更多的问题花费尽可能多的时间,并提供了更多的细节:)