Hommer Smith
Hommer Smith

Reputation: 27862

Regex to find price in HTML

Disclaimer: I know that parsing HTML with regex is not the correct approach. I am actually just trying to parse text inside the HTML.

I am parsing several pages, and I am looking for prices. Here is what I have so far:

var all = document.body.querySelectorAll(":not(script)");
var regex = /\$[0-9,]+(\.[0-9]{2})?/g;

for (var i = 0; i < all.length; i++) {

    var node_value = all[i].nodeValue;
        for (var j = 0; j < all[i].childNodes.length; j++) {

            var node_value = all[i].childNodes[j].nodeValue;
            if (node_value !== null) {

                var matches = node_value.match(regex);
                if (matches !== null && matches.length > 0) {

                    alert("that's a match");
                }
            }
        }
}

This particular code can get me prices like this:

<div>This is the current price: <span class="current">$60.00</span></div>

However, there are some prices that have the following structure:

<div>This is the current price: <sup>$</sup><span>80.00</span></div>

How could I improve the algorithm in order to find those prices? Shall I look in the first for loop for <sup>symbol</sup><span>price</span> with regex?

Important: Once a match, I need to findout which DOM element is holding that price. The most inner element that is holding the price. So for example:

<div><span>$80.00</span></div>

I would need to say that is the element that is holding the price, not the div.

Upvotes: 1

Views: 2347

Answers (2)

Niet the Dark Absol
Niet the Dark Absol

Reputation: 324830

Try this:

var text = document.body.textContent || document.body.innerText,
    regex = /\$\s*[0-9,]+(?:\s*\.\s*\d{2})?/g,
    match = text.match(regex);
if( match) {
    match = match[0].replace(/\s/g,"");
    alert("Match found: "+match);
}

Using a recursive search:

function findPrice(node) {
    node = node || document.body;
    var text = node.textContent || node.innerText,
        regex = /\$\s*[0-9,]+(?:\s*\.\s*\d{2})?/,
        match = text.match(regex);
    if( match) {
        var children = node.children, l = children.length, i;
        for( i=0; i<l; i++) {
            if( findPrice(children[i])) {
                return children[i];
            }
        }
        // if no children matched, then this is the narrowest container
        return node;
    }
    else return false;
}
var result = findPrice();

Upvotes: 1

halfbit
halfbit

Reputation: 3464

If you can choose your browser, you might use XPath to pre-select your candidates. The following code finds candidates nodes. I tried it in Firefox 25. You might also want to look at What browsers support Xpath 2.0? and http://www.yaldex.com/ajax-tutorial-4/BBL0029.html for cross-browser approaches.

<html><head><script type="text/javascript">
function func() {
  //span containing digits preceeded by superscript dollar sign
  var xpathExpr1 = "//span[translate(text(),'0123456789.,','')!=text()][preceding-sibling::sup[text()='$']]";
  //span containing digits and starting with dollar sign
  var xpathExpr2 = "//span[translate(text(),'0123456789.,','')!=text() and contains(text(),'$')]";
  var xpathExpr3 = xpathExpr1 + "|" + xpathExpr2; // union
  var contextNode = document.body;
  var namespaceResolver = function(prefix){return "";}
  var resultType = XPathResult.UNORDERED_NODE_ITERATOR_TYPE;
  var xpathResult = document.evaluate(xpathExpr1, contextNode, namespaceResolver, resultType, null);
  alert(xpathResult);
  var node;
  while ((node = xpathResult.iterateNext()) != null) {
      alert(node.textContent);
  }
}
</script></head>
<body onload="func()"> aaa
<sup>$</sup><span>80.00</span> bbb
<span>$129</span> ccc
<sup>$</sup><span>ABC</span> ddd
</body></html>

Upvotes: 0

Related Questions