title: Regex to extract US zip codes but not faux codes
body: <p>Using the XML package and XPath to scrape addresses from websites, I sometimes can get only a string that has embedded in it the zip code I want.  It is straightforward to extract the zip code, but sometimes there are other five-digit strings that show up.  </p>
  
  <p>Here are some variations on the problem in a df.</p>
  
  <pre><code>zips &lt;- data.frame(id = seq(1, 5), address = c("Company, 18540 Main Ave., City, ST 12345", "Company 18540 Main Ave. City ST 12345-0000", "Company 18540 Main Ave. City State 12345", "Company, 18540 Main Ave., City, ST 12345 USA", "Company, One Main Ave Suite 18540, City, ST 12345")) 
  </code></pre>
  
  <p>The R statement to extract zip codes (both 5 digit and plus 4 digits) is below, but it is tricked by the faux zip codes of the street number and the suite number (and there may be other possibilities in other address strings).</p>
  
  <pre><code>regmatches(zips$address, gregexpr("\\d{5}([-]?\\d{4})?", zips$address, perl = TRUE))
  </code></pre>
  
  <p>An answer to a previous SO question suggested that a "regex will return the last consecutive five digit string. It uses a negative look-ahead to ensure the absence of 5-digit strings after the one being returned."<br>
  <a href="https://stackoverflow.com/questions/21074812/extracting-a-zip-code-from-an-address-string">Extracting a zip code from an address string</a></p>
  
  <pre><code>\b\d{5}\b(?!.*\b\d{5}\b)
  </code></pre>
  
  <p>But that question and answer deals with PHP and offers an if loop with preg_matches()`  I am not familiar with those languages and tools, but the idea might be right.</p>
  
  <p>My question: what R code will find real zip codes and ignore false lookalikes?</p>