{"id":64843,"date":"2007-05-17T22:58:00","date_gmt":"2007-05-17T22:58:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2007\/05\/17\/how-can-i-search-for-phone-numbers-in-a-text-file\/"},"modified":"2007-05-17T22:58:00","modified_gmt":"2007-05-17T22:58:00","slug":"how-can-i-search-for-phone-numbers-in-a-text-file","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/how-can-i-search-for-phone-numbers-in-a-text-file\/","title":{"rendered":"How Can I Search For Phone Numbers in a Text File?"},"content":{"rendered":"<p><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" height=\"34\" alt=\"Hey, Scripting Guy! Question\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\"> \n<P>Hey, Scripting Guy! I have a bunch of text files, one for each of our employees. Included in these text files are phone numbers: work phone, home phone, cell phone, etc. How can I write a script that searches for and extracts the phone numbers from these text files?<BR><BR>&#8212; MN<\/P><IMG height=\"5\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" border=\"0\"><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" height=\"34\" alt=\"Hey, Scripting Guy! Answer\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\"><A href=\"http:\/\/go.microsoft.com\/fwlink\/?linkid=68779&amp;clcid=0x409\"><IMG class=\"farGraphic\" title=\"Script Center\" height=\"288\" alt=\"Script Center\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/ad.jpg\" width=\"120\" align=\"right\" border=\"0\"><\/A> \n<P>Hey, MN. You know, many years ago the Scripting Guy who writes this column read <A href=\"http:\/\/www.douglasadams.com\/creations\/hhgg.html\" target=\"_blank\"><B><I>The Hitchhiker\u2019s Guide to the Galaxy<\/I><\/B><\/A>. Now, being a Scripting Guy, he can\u2019t help but admire anyone who writes a trilogy that actually contains five books. However, he still feels obligated to point out that the <I>Hitchhiker\u2019s Guide<\/I> informed everyone that the answer to the ultimate question of life, the universe, and everything (a question that hasn\u2019t even been asked yet) is 42. Sorry, but that\u2019s simply not right. Instead, the correct answer is 1301.<\/P>\n<P>Why 1301? Well, we\u2019re assuming that the ultimate question of life, the universe, and everything is this: if I go to <A href=\"http:\/\/www.microsoft.com\/events\/teched2007\/default.mspx\" target=\"_blank\"><B>TechEd 2007<\/B><\/A> in Orlando, how in the world will I ever track down the Scripting Guys? The answer? By remembering the magic number: 42.<\/P>\n<P>Oh, wait; sorry. The magic number is <B>1301<\/B>, not 42. Go into the Partners Expo and look for booth 1301, the CMP Media booth. See the guy in a ratty old black hat with the word <I>Japan<\/I> on it and the woman with a bunch of <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/topics\/mms2007\/tuesday.mspx\"><B>staples in her head<\/B><\/A>? Well, there you go: you just found the Scripting Guys. We\u2019re interested in talking to as many people as we can (or, to be more accurate, as many people as we can before we can slip out the back door and head for <A href=\"http:\/\/disneyworld.disney.go.com\/wdw\/parks\/attractionDetail?id=SplashMountainAttractionPage\" target=\"_blank\"><B>Splash Mountain<\/B><\/A>.) So if you find yourself in Orlando June 4-8 be sure to drop by and say hi, and to give us an idea of what we can do to serve you better.<\/P>\n<P>Remember that number: 1301. The same year that Scripting Guy Peter Costantini was born.<\/P>\n<P>Now that we know the answer to the ultimate question of life it\u2019s time to turn our attention to the next ultimate question of life: how can I extract phone numbers from a text file? According to MN\u2019s email she has a series of text files, each of them looking something like this:<\/P><PRE class=\"codeSample\">Ken Myer\nAccountant\nFabrikam, North American Division\nBuilding 16, Room 129\nRedmond, WA 98052\n425-555-1212 (office), 425-555-5656 (cell)\nWife\u2019s name: Sarah\nChildren: Robert (4), Teri (2)\n425-555-3434 (home)\n<\/PRE>\n<P>What MN needs to do is read through these files and extract the phone numbers, like so:<\/P><PRE class=\"codeSample\">425-555-1212 (office)\n425-555-5656 (cell)\n425-555-3434 (home)\n<\/PRE>\n<P>That doesn\u2019t sound too hard, does it? Unfortunately though, there\u2019s at least one complication: the text files are not necessarily consistent. For example, in Ken Myer\u2019s text file his home phone appears on line 9. However, suppose Ken wasn\u2019t married and suppose he didn\u2019t have any children. In that case, his text file would look like this, and his home phone would appear on line 7:<\/P><PRE class=\"codeSample\">Ken Myer\nAccountant\nFabrikam, North American Division\nBuilding 16, Room 129\nRedmond, WA 98052\n425-555-1212 (office), 425-555-5656 (cell)\n425-555-3434 (home)\n<\/PRE>\n<P>Likewise, while the phone numbers will always be in the same format: <B>Area Code-Prefix-Suffix (phone type)<\/B>, the area codes can (and will) differ, as will the phone types. For example, some people don\u2019t have cell phones. In other words, about all we can do is search for a particular pattern and then report back each instance of that pattern. But how in the world can we do <I>that<\/I>?<\/P>\n<P>Well, here\u2019s one way:<\/P><PRE class=\"codeSample\">Const ForReading = 1<\/p>\n<p>Set objFSO = CreateObject(&#8220;Scripting.FileSystemObject&#8221;)\nSet objFile = objFSO.OpenTextFile(&#8220;C:\\Scripts\\Ken_myer.txt&#8221;, ForReading)<\/p>\n<p>strSearchString = objFile.ReadAll<\/p>\n<p>objFile.Close<\/p>\n<p>Set objRegEx = CreateObject(&#8220;VBScript.RegExp&#8221;)<\/p>\n<p>objRegEx.Global = True   \nobjRegEx.Pattern = &#8220;\\d{3}-\\d{3}-\\d{4} \\([a-zA-Z]*\\)&#8221;<\/p>\n<p>Set colMatches = objRegEx.Execute(strSearchString)  <\/p>\n<p>If colMatches.Count &gt; 0 Then\n   For Each strMatch in colMatches   \n       Wscript.Echo strMatch.Value \n   Next\nEnd If\n<\/PRE>\n<P>Before we begin explaining how this script works, take a deep breath and relax: this is nowhere near as complicated as it might look. As you can see, we actually start off in very simple fashion, defining a constant named ForReading and setting the value to 1. (We\u2019ll need this constant when we go to open the text file). Speaking of which, our next two steps are to create an instance of the <B>Scripting.FileSystemObject<\/B> object and then use the <B>OpenTextFile<\/B> method to open the file C:\\Scripts\\Ken_myer.txt:<\/P><PRE class=\"codeSample\">Set objFSO = CreateObject(&#8220;Scripting.FileSystemObject&#8221;)\nSet objFile = objFSO.OpenTextFile(&#8220;C:\\Scripts\\Ken_myer.txt&#8221;, ForReading)\n<\/PRE>\n<P>As soon as the file is open we use the <B>ReadAll<\/B> method to read in the entire file and store the contents in a variable named strSearchString. And once we have the contents stashed safely away in strSearchString we go ahead and close the text file.<\/P>\n<P>Now comes the tricky part.<\/P>\n<P>If we were searching for a particular value (e.g., the phone number 425-555-1212) we could simply use VBScript\u2019s InStr function. However, we aren\u2019t interested in any one phone number; as we noted before, we\u2019re really look for a phone number pattern. Any time you\u2019re searching for a pattern you need to use a regular expression. That\u2019s also true for the Scripting Guys: any time we\u2019re searching for a pattern we need to use a regular expression. Hence the next line of code, which creates an instance of the <B>VBScript.RegExp<\/B> object:<\/P><PRE class=\"codeSample\">Set objRegEx = CreateObject(&#8220;VBScript.RegExp&#8221;)\n<\/PRE>\n<TABLE class=\"dataTable\" id=\"EHF\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P class=\"lastInCell\"><B>Note<\/B>. If you\u2019re already lost you might want to take a look at <A href=\"http:\/\/www.microsoft.com\/events\/EventDetails.aspx?CMTYSvcSource=MSCOMMedia&amp;Params=%7eCMTYDataSvcParams%5e%7earg+Name%3d%22ID%22+Value%3d%221032271679%22%2f%5e%7earg+Name%3d%22ProviderID%22+Value%3d%22A6B43178-497C-4225-BA42-DF595171F04C%22%2f%5e%7earg+Name%3d%22lang%22+Value%3d%22en%22%2f%5e%7earg+Name%3d%22cr%22+Value%3d%22US%22%2f%5e%7esParams%5e%7e%2fsParams%5e%7e%2fCMTYDataSvcParams%5e\" target=\"_blank\"><B>String Theory for System Administrators<\/B><\/A>, Scripting Guy Dean Tsaltas\u2019 immortal introduction to regular expressions for regular people.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>Once we have a regular expression object we need to configure two key properties of that object. First, we set the <B>Global<\/B> property to True; this tells the regular expression object that we want to search the entire target string (strSearchString) for all instances of the pattern. If Global is set to False then the regular expression object will find the first instance of the pattern and then stop. In this case, that\u2019s no good: it would find the first phone number and then quit, without looking for any additional phone numbers for Ken Myer.<\/P>\n<P>And then it\u2019s time to define our search <B>Pattern<\/B>:<\/P><PRE class=\"codeSample\">objRegEx.Pattern = &#8220;\\d{3}-\\d{3}-\\d{4} \\([a-zA-Z]*\\)&#8221;\n<\/PRE>\n<P>Maybe you better sit down; you look a little dizzy. That\u2019s the problem with regular expressions: you take one look at the syntax and your first thought is to panic. Listen, don\u2019t panic (as the <I>Hitchhiker\u2019s Guide<\/I> repeatedly implored). Regular expression syntax isn\u2019t very pretty, but it <I>can<\/I> be explained.<\/P>\n<P>To begin with, our phone numbers always start with the area code; that means a phone number will always start with three numbers back-to-back-to-back. Because of that, our regular expression also starts with three numbers; that\u2019s what the <B>\\d{3}<\/B> is for. (The <B>\\d<\/B> means digits, the <B>{3}<\/B> means there must be three consecutive digits.) After the area code we have a hyphen followed by three more digits (the prefix). And guess what? In our regular expression we also have a hyphen followed by three more digits (again using <B>\\d{3}<\/B>). In the phone number the prefix is followed by another hyphen and four more digits. And in our regular expression \u2013 that\u2019s right, we have the exact same thing: <B>\\d{4}<\/B>. (Note that we use the syntax <B>{4}<\/B> because we\u2019re now looking for <I>four<\/I> consecutive digits.)<\/P>\n<P>That\u2019s actually all the information we need to find phone numbers. However, each phone number of followed by a parenthetical statement that tells us the type of phone number (e.g., <B>(cell)<\/B>). We thought it might be nice to grab these parenthetical statements as well. Therefore, we decided to gussy up our pattern a little bit.<\/P>\n<P>So <I>how<\/I> did we gussy up our pattern? Well, if you look closely you\u2019ll see there\u2019s a blank space immediately following the telephone suffix; that corresponds to the blank space in a phone number like <B>425-555-1212 (office)<\/B>. Following the blank space we use this construction to represent the opening parenthesis: <B>\\(<\/B>. (Why the <B>\\<\/B> before the parenthesis? That\u2019s because the open and close parentheses are reserved characters in regular expressions. The \\ simply tells the script to look for the actual open parenthesis character; that is, look for the <B>(<\/B> character.)<\/P>\n<P>You might note that, at the end of the pattern, we use a similar construction to represent the close parenthesis: <B>\\)<\/B>.<\/P>\n<P>OK, so open and close parentheses aren\u2019t too hard. But what about the stuff that goes <I>between<\/I> the parentheses? At the very least that could be <I>office<\/I>, <I>cell<\/I>, or <I>home<\/I>; how do we search for something that could be almost anything?<\/P>\n<P>To be honest, there are probably all sorts of ways to do that. (Regular expressions are nothing it not flexible.) Because everything within the parentheses is going to be a word (of some kind) we decided to go this route:<\/P><PRE class=\"codeSample\">[a-zA-Z]*\n<\/PRE>\n<P>We\u2019ve actually got several things going on here. To begin with, we\u2019re interested only in letters, either lowercase or uppercase. In a regular expression, you can search for a range of values by enclosing that range within square brackets and by using hyphens as needed. Inside our square brackets we actually have two items: <B>a-z<\/B> and <B>A-Z<\/B>. The a-z syntax simply says, \u201cFind anything that begins with a lowercase letter (a-z)\u201d; as you might expect, the A-Z syntax says \u201cFind anything that begins with an uppercase letter (A-Z).\u201d The net effect is that we\u2019re searching for any letter (lowercase or uppercase). If there\u2019s a number or a punctuation mark or anything but the letters A through Z then this won\u2019t be considered a match.<\/P>\n<P>OK, so we\u2019re searching for letters (and only letters) enclosed in parentheses. But how <I>many<\/I> letters are we searching for? Well, we don\u2019t know. The word <I>office<\/I> has 5 letters; the word <I>cell<\/I> has 4. Technically, we\u2019re looking for 0 or more letters; that\u2019s what the asterisk (*) represents. In other words, we\u2019re looking for a phone number, followed by a blank space, followed by a parenthetical statement that contains 0 or more letters (and only letters).<\/P>\n<P>Confused? We don\u2019t blame you. Truthfully, the best way to understand how regular expressions work is to play with them a bit. For example, try removing the <B>a-z<\/B> section from the pattern and then running the script. The script won\u2019t find any phone numbers. Why not? Because, with a-z removed, all that\u2019s left is A-Z, meaning that we\u2019re looking <I>only<\/I> for uppercase letters (e.g., <I>OFFICE<\/I>). Now, go into the text file, make everything uppercase, and try the script again. <\/P>\n<P>Speaking of trying the script, here\u2019s what we get back when <I>we<\/I> try the script:<\/P><PRE class=\"codeSample\">425-555-1212 (office)\n425-555-5656 (cell)\n425-555-3434 (home)\n<\/PRE>\n<P>Which is exactly what we <I>wanted<\/I> to get back.<\/P>\n<P>OK, so now we know how to locate phone numbers in a text file. That\u2019s good, but it doesn\u2019t fully answer MN\u2019s question; after all, she asks how to perform this task on scores of text files. That\u2019s a good question, and it\u2019s one we get asked quite a bit: how do I perform the same task on a whole bunch of text files, all at the same time. That\u2019s something we\u2019ll address tomorrow, as the conclusion to a rare two-part <I>Hey, Scripting Guy!<\/I> column.<\/P>\n<TABLE class=\"dataTable\" id=\"E3BAC\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P class=\"lastInCell\"><B>Note<\/B>. Will that result in these two columns becoming a collector\u2019s item of some kind? Sure; why not?<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>In conclusion, remember, that\u2019s booth <B>1301<\/B> (the CMP Media booth) in the Partners Expo hall. The Scripting Guys will be there, they\u2019ll have a fun little giveaway for everyone, and you\u2019ll have the opportunity to win your very own <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/bobbles.mspx\"><B>Dr. Scripto bobblehead<\/B><\/A> doll. <\/P>\n<P>Actually we should clarify that a bit: Scripting Guy Greg Stemp will be there in booth 1301. However, if her trip to Florida goes anything like her trip to San Diego you\u2019ll need to go to the Orlando Regional Medical Center if you want to talk to Scripting Guy Jean Ross. But be sure and drop by there and say hi. (And maybe give her a pint of blood or something while you\u2019re there.) <I>Editor\u2019s Note: Scripting Guy Jean Ross had the staples removed weeks ago, is perfectly healthy, and will be in booth 1301. Or so she insists.<\/I><\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! I have a bunch of text files, one for each of our employees. Included in these text files are phone numbers: work phone, home phone, cell phone, etc. How can I write a script that searches for and extracts the phone numbers from these text files?&#8212; MN Hey, MN. You know, many [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[3,4,14,5],"class_list":["post-64843","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-scripting-guy","tag-scripting-techniques","tag-text-files","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! I have a bunch of text files, one for each of our employees. Included in these text files are phone numbers: work phone, home phone, cell phone, etc. How can I write a script that searches for and extracts the phone numbers from these text files?&#8212; MN Hey, MN. You know, many [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/64843","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=64843"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/64843\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=64843"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=64843"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=64843"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}