Showing posts with label stringmatchq. Show all posts
Showing posts with label stringmatchq. Show all posts

Friday, December 11, 2015

String Processing: Validate Email Address Format, Part 1

Here are three approaches to predicates validating that an email address has an "@" sign and a period ".". A true email address validator is much more complicated, so these functions are merely to illustrate some String processing techniques. That said, I did use the first approach to validate thousands of email addresses and flush out bad ones.

The first predicate uses StringMatchQ and the essential idea is to give StringMatchQ a String pattern representing:
  1. An "@" wildcard for at least one but an unknown number of characters
  2. Followed by the "@" sign as used in an email address to separate localpart from domain
  3. Followed by the wildcard again
  4. Followed by the period "." used to separate the mail server name from the top-level domain
  5. Followed by the wildcard
Note that an asterisk wildcard ("*") would not be suitable since each position in the pattern has at least one character.

The first variation illustrates the use of Verbatim, which tells Mathematica to treat the middle "@" sign as an "@" sign  (read it "verbatim") and not as a pattern wildcard.

Clear@emailAddressQ1;emailAddressQ1@aString_String:=StringMatchQ[aString,"@"~~Verbatim@"@"~~"@.@"]

The second variation of StringMatchQ does the same thing but more concisely, using a double backslash. The first backslash tells Mathematica to treat the second one as an 'escape' character, which then tell Mathematica to treat the "@" sign as an "@" sign and not as a wildcard.

Clear@emailAddressQ1a;emailAddressQ1a@aString_String:=StringMatchQ[aString,"*\\@*.*"]

The second basic approach uses StringContainsQ to detect the presence of the "@" sign and period "." in the address. Since it doesn't require additional characters in the correct positions as does the first approach, it is not as good a validator.

Clear@emailAddressQ2;emailAddressQ2@aString_String:=StringContainsQ[aString,"@"]&&StringContainsQ[aString,"."]

The third approach uses StringFreeQ to see if the address has no "@" sign and period ".", and some logic, and suffers the same limitation as the second approach.

Clear@emailAddressQ3;emailAddressQ3@aString_String:=Not[StringFreeQ[aString,"@"]&&StringFreeQ[aString,"."]]

Test Cases


The test cases are 1) valid email format, 2) missing "@" sign, 3) missing "." and 4) missing both "@" and ".".

testCases={"abc@dwxy.anything","abcdwxy.anything","abc@dwxyanything","abcdwxyanything"};

emailAddressQ1/@testCases

{True,False,False,False}

emailAddressQ1a/@testCases

{True,False,False,False}

emailAddressQ2/@testCases

{True,False,False,False}

emailAddressQ3/@testCases

{True,True,True,False}

Aha! The test cases flushed out a logic error. The way the emailAddressQ3 function is written with the AND (&&) conjunction between the two clauses, only if both StringMatchQ tests are FALSE will AND return FALSE and be negated by NOT into TRUE. We need to change the AND to OR so that if either "@" or "." are missing, the OR returns TRUE and is negated by NOT into FALSE.

Clear@emailAddressQ4;emailAddressQ4@aString_String:=Not[StringFreeQ[aString,"@"]||StringFreeQ[aString,"."]]

emailAddressQ4/@testCases

{True,False,False,False}

Wednesday, May 27, 2015

An Example Using Pick to Select Data by Pattern Instead of Cases, Select, or StringCases

Pick

Prefatory remark: To learn Mathematica efficiently you should focus on the most-frequently-used functions. I will provide a list of those soon. For most users Pick[] will not be a frequently-used function. You can learn "esoteric" Mathematica functions just for fun or because in your work certain esoteric functions are handy.

Here, nonetheless, is an example spawned from my not being able to get StringCases to work (solved and explained here), altho strangely StringMatchQ does work, which is the standard way to see if StringCases will work.

This is a file header from a parameter sweep I did in the finite element modeling program COMSOL. The goal is to select the different parameters used in the sweep, which are voltages such as "VCathode=2.29025"; I don't need all the other noise in there.

The way the command works is: 1) StringMatchQ is mapped onto data, which is a List of Strings, and returns True if the target matches the String with "*" wildcard, or False otherwise; 2) Pick then scans data to find instances matching the selection pattern. In this case since Pick's default selection pattern is True, I didn't need to use its 3rd argument that specifies a different selection pattern (such as "1" vs. "0").

data = {"%","cln1x","V","(V)","@","VCathode=2.75392","V","(V)","@","VCathode=2.29025","V","(V)","@","VCathode=1.86092","V","(V)","@","VCathode=1.59846","V","(V)","@","VCathode=1.40122","V","(V)","@","VCathode=1.28137","V","(V)","@","VCathode=1.15876","V","(V)","@","VCathode=1.06451","V","(V)","@","VCathode=1.0037","V","(V)","@","VCathode=0.950678","V","(V)","@","VCathode=0.881652","V","(V)","@","VCathode=0.836608","V","(V)","@","VCathode=0.795234","V","(V)","@","VCathode=0.753297","V","(V)","@","VCathode=0.73737","V","(V)","@","VCathode=0.725229","V","(V)","@","VCathode=0.703015","V","(V)","@","VCathode=0.68059","V","(V)","@","VCathode=0.646921","V","(V)","@","VCathode=0.62848"};

Pick[data,StringMatchQ[#,"VCathode*"]&/@data]

{VCathode=2.75392,VCathode=2.29025,VCathode=1.86092,VCathode=1.59846,VCathode=1.40122,VCathode=1.28137,VCathode=1.15876,VCathode=1.06451,VCathode=1.0037,VCathode=0.950678,VCathode=0.881652,VCathode=0.836608,VCathode=0.795234,VCathode=0.753297,VCathode=0.73737,VCathode=0.725229,VCathode=0.703015,VCathode=0.68059,VCathode=0.646921,VCathode=0.62848}

My next step will be to use Table and Join to insert the correct parameter in the header of the its matching data file from COMSOL.

Trivia: Pick was originally called BinarySelect and Stephen Wolfram re-named it, as is his want, to a short Anglo-Saxon term (a large metal rod is called a pick, or think of using toothpick to pick up food). I ran into him at a ice cream shop and complimented him on the function and asked if he had re-named it. When he was much younger Stephen ate a lot of chocolate and didn't take care of himself physically. But that has changed, he is careful with his diet and spends a lot of time on the treadmill staying in good physical condition.

Friday, April 11, 2014

Create Predicates to Test Strings vs Numerics: Test for File Extensions

Elsewhere I tell why predicates are important to use, show how to find all predicates in Mathematica including ones not suffixed with "Q"and create ones of your own to test numerical expressions. Here I cover predicates for testing Strings, and create some tests for file types, as judged by their extensions. Note that FileExtension does not capture the period before the extension.

Equal (==) and SameQ (===) are valid predicates for Strings as well as numerics, and work fine for simple applications.

In[206]:= uncusFileQ@fileName_String := FileExtension@fileName == "unc"

In[207]:= uncusFileQ@"afile.unc"

Out[207]= True

In[208]:= uncusFileQ@"afile.txt"

Out[208]= False

In[209]:= textFileQ@fileName_String := FileExtension@fileName == "txt"

In[215]:= textFileQ@"sampleFile.txt"

Out[215]= True

To test for two alternative file extensions is a little trickier. Since we are testing for String equivalence between String patterns, we use the general String predicate function StringMatchQ and Alternatives (|), not logical Or (||). An example is testing for HTML files, since their extensions come in .htm and .html flavors.

In[210]:= Clear@htmlFileQ;
htmlFileQ@fileName_String := StringMatchQ[FileExtension@fileName, "html" | "htm"]

In[212]:= htmlFileQ@"www.jognog.com/index.html"

Out[212]= True

In[213]:= htmlFileQ@"www.jognog.com/index.htm"

Out[213]= True

In[214]:= htmlFileQ@"www.jognog.com/sitemap.xml"

Out[214]= False


Monday, January 2, 2012

Assignment to a Pattern


I'll use a couple of examples on searching Strings from Sal Mangano's excellent Mathematica Cookbook to show how to use Pattern Assignment. First, it's simple enough to search some Strings for those that are numbers:

StringMatchQ[{"12345", "2468", "abcde"}, NumberString]

{True, True, False}

But if you want to add a Predicate, you need another device such as naming a Pattern and using the name in the Predicate. This is an example of Pattern Assignment where the Pattern is named "m".

StringMatchQ[{"12345", "2468", "abcde"}, m : NumberString /; OddQ@FromDigits@m]

{True, False, False}

As Sal Mangone notes in his Mathematica Cookbook and I explore further in Predicates, Tests, and Test Patterns, adding a Predicate to a Pattern is a powerful device because we can include in the Predicate anything that Mathematica can compute. A Predicate can be a built-in one or one we construct, so the possibilities are truly limitless.