我有此正则表达式表达式,用于搜索电话号码模式:
[(]?\d{3}[)]?[(\s)?.-]\d{3}[\s.-]\d{4}
这与以下格式的电话号码匹配:
123 456 7890 (123)456 7890 (123) 456 7890 (123)456-7890 (123) 456-7890 123.456.7890 123-456-7890
我想扫描整个页面(使用JavaScript)以查找此匹配项,但不包括锚点中已存在的此匹配项。找到匹配项后,我要将电话号码转换为移动设备的点击通话链接:
(123) 456-7890 --> (123) 456-7890
我很确定我需要做一个否定查询。我已经尝试过了,但这似乎不是正确的主意:
(?!.*(\))[(]?\d{3}[)]?[(\s)?.-]\d{3}[\s.-]\d{4}
ShadowRanger.. 5
不要使用正则表达式来解析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 // Insert new elements before existing element; first element is just // text before first phone number parent.insertBefore(document.createTextNode(numbers[0]), txt); // Now explicitly create pairs of anchors and following text nodes for (var j = 1; j < numbers.length; j += 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[j].replace(/\D+/g, ''); anc.textContent = numbers[j]; parent.insertBefore(anc, txt); parent.insertBefore(document.createTextNode(numbers[j+1]), txt); } // Remove original text node now that we've inserted all the // replacement elements and don't need it for positioning anymore parent.removeChild(txt); parent.normalize(); // Normalize whitespace after rebuilding } }
作为记录,基本过滤器在大多数页面上都有很大帮助。例如,在此页面上,现在,如我所见(随用户,浏览器,浏览器扩展和脚本等的不同而有所不同),如果没有过滤器,则该查询的快照'descendant-or-self::text()'
将包含1794个项目。省略由锚标记标记的文本,'descendant-or-self::text()[not(parent::A)]'
将其降至1538,然后执行完整查询,以验证非空白内容的长度至少为十二个字符,从而将其降至87项。在性能上,将正则表达式应用于87个项是不合常规的更改,并且您不再需要使用不合适的工具来解析HTML。
不要使用正则表达式来解析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 // Insert new elements before existing element; first element is just // text before first phone number parent.insertBefore(document.createTextNode(numbers[0]), txt); // Now explicitly create pairs of anchors and following text nodes for (var j = 1; j < numbers.length; j += 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[j].replace(/\D+/g, ''); anc.textContent = numbers[j]; parent.insertBefore(anc, txt); parent.insertBefore(document.createTextNode(numbers[j+1]), txt); } // Remove original text node now that we've inserted all the // replacement elements and don't need it for positioning anymore parent.removeChild(txt); parent.normalize(); // Normalize whitespace after rebuilding } }
作为记录,基本过滤器在大多数页面上都有很大帮助。例如,在此页面上,现在,如我所见(随用户,浏览器,浏览器扩展和脚本等的不同而有所不同),如果没有过滤器,则该查询的快照'descendant-or-self::text()'
将包含1794个项目。省略由锚标记标记的文本,'descendant-or-self::text()[not(parent::A)]'
将其降至1538,然后执行完整查询,以验证非空白内容的长度至少为十二个字符,从而将其降至87项。在性能上,将正则表达式应用于87个项是不合常规的更改,并且您不再需要使用不合适的工具来解析HTML。