这是参考我上周发布的question。
我想在页面上查找所有有效的电话号码。如果它们尚未在链接中,我想创建一个“点击呼叫”链接以在移动浏览器上使用。 我在发布的原始问题上收到了几个很好的答案,但是想尝试不同的方法/扩展反馈。
我正在使用jQuery和Regex来过滤页面内容并使链接可以点击。
以下是我的想法:
var phoneRegex = new RegExp(/([(]?\d{3}[)]?[(\s)?.-]\d{3}[\s.-]\d{4})(?![^<]*>|[^<>]*<\/)/g);
var phoneNums = $( "body *" ).filter(function() {
var tagname = $(this).prop("tagName");
tagname = tagname === null ? "" : tagname.toLowerCase();
if (tagname == "a") {
return false;
}
var match = $(this).html().match(phoneRegex);
if (match === null || match.length === 0) {
return false;
}
return true;
});
phoneNums.html(function() {
var newhtml = $(this).html().replace(phoneRegex, function(match) {
var phonenumber = match.replace(/ /g, "").replace(/-/g, "").replace(/\(/g, "").replace(/\)/g, "");
var link = '<a href="tel:' + phonenumber + '">' + match + '</a>';
return link;
});
return newhtml;
});
所以,基本上我搜索身体中寻找每个标签的一切(不包括锚标签)。我匹配正则表达式并将值存储在'phoneNums'变量中。
从那里我删除所有空格,破折号和括号,以便数字将正确格式化tel属性。
所以像这样的数字:(123)456-7890将格式如下:<a href="tel:1234567890">(123) 456-7890</a>
我看到这样做的问题是如果这些数字是在页面上的嵌套标签中,我会多次得到结果。 (如果您在链接上执行console.log,就会在返回之前看到这一点。)结果是正确的,但想知道这是否有意义。
有更有效的方法吗?提前致谢!
答案 0 :(得分:1)
和以前一样(在我更新它以包含执行元素替换的代码后,从原始问题复制粘贴)Don't use regular expressions to parse HTML。使用HTML / DOM解析器获取文本节点(浏览器可以为您过滤掉它,删除锚标签以及所有文本都太短而不能包含电话号码),您可以直接检查文本。
例如,使用XPath(有点难看,但支持直接处理文本节点,大多数其他DOM方法都没有):
// This query finds all text nodes with at least 12 non-whitespace characters
// who are not direct children of an anchor tag
// Letting XPath apply basic filters dramatically reduces the number of elements
// you need to process (there are tons of short and/or pure whitespace text nodes
// in most DOMs)
var xpr = document.evaluate('descendant-or-self::text()[not(parent::A) and string-length(normalize-space(self::text())) >= 12]',
document.body, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
for (var i=0, len=xpr.snapshotLength; i < len; ++i) {
var txt = xpr.snapshotItem(i);
// Splits with grouping to preserve the text split on
var numbers = txt.data.split(/([(]?\d{3}[)]?[(\s)?.-]\d{3}[\s.-]\d{4})/);
// split will return at least three items on a hit, prefix, split match, and suffix
if (numbers.length >= 3) {
var parent = txt.parentNode; // Save parent before replacing child
// Replace contents of parent with text before first number
parent.textContent = numbers[0];
// Now explicitly create pairs of anchors and following text nodes
for (var i = 1; i < numbers.length; i += 2) {
// Operate in pairs; odd index is phone number, even is
// text following that phone number
var anc = document.createElement('a');
anc.href = 'tel:' + numbers[i].replace(/\D+/g, '');
anc.textContent = numbers[i];
parent.appendChild(anc);
parent.appendChild(document.createTextNode(numbers[i+1]));
}
parent.normalize(); // Normalize whitespace after rebuilding
}
}
对于记录,基本过滤器可帮助大多数页面上的批次。例如,在此页面上,正如我所看到的(根据用户,浏览器,浏览器扩展和脚本等因素而不同),如果没有过滤器,查询'descendant-or-self::text()'
的快照将包含1794项。省略锚标记的父级文本,'descendant-or-self::text()[not(parent::A)]'
将其降低到1538,并且验证非空白内容至少为12个字符长的完整查询将其归结为87个项目。将正则表达式应用于87个项目是笨拙的改变,性能方面,并且您已经无需使用不合适的工具解析HTML。