{"id":55743,"date":"2008-04-19T01:12:00","date_gmt":"2008-04-19T01:12:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2008\/04\/19\/hey-scripting-guy-how-can-i-parse-a-text-file-and-retrieve-all-the-information-contained-within-square-brackets\/"},"modified":"2008-04-19T01:12:00","modified_gmt":"2008-04-19T01:12:00","slug":"hey-scripting-guy-how-can-i-parse-a-text-file-and-retrieve-all-the-information-contained-within-square-brackets","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-parse-a-text-file-and-retrieve-all-the-information-contained-within-square-brackets\/","title":{"rendered":"Hey, Scripting Guy! How Can I Parse a Text File and Retrieve All the Information Contained Within Square Brackets?"},"content":{"rendered":"<p><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\" \/> <\/p>\n<p>Hey, Scripting Guy! I need to parse through a text file and extract the information contained within square brackets. So far, however, I haven\u2019t been able to figure out how to do this; that\u2019s because the data isn\u2019t stored on separate lines in the file. Can you help?<br \/>&#8212; EI<\/p>\n<p><img decoding=\"async\" border=\"0\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" height=\"5\" \/><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\" \/><a href=\"http:\/\/go.microsoft.com\/fwlink\/?linkid=68779&amp;clcid=0x409\"><img decoding=\"async\" class=\"farGraphic\" title=\"Script Center\" border=\"0\" alt=\"Script Center\" align=\"right\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/ad.jpg\" width=\"120\" height=\"288\" \/><\/a> <\/p>\n<p>Hey, EI. Well, today is Friday, April 18<sup>th<\/sup>, the day the National Basketball Association is supposed to vote on whether the league will allow the Seattle Sonics to be moved to Oklahoma City. To be honest, the Scripting Guy who writes this column couldn\u2019t care less; after all, he doesn\u2019t like the NBA (he likes <i>basketball<\/i>) and he hasn\u2019t watched a Sonic game in years, not even on TV. Nevertheless, he <i>has<\/i> been fascinated by the soap opera playing out between the city of Seattle and the Sonics owners, Oklahoma natives who promised to do everything possible to keep the team in the state of Washington and then \u2013 as recently-released emails have shown \u2013 pretty much did everything possible <i>not<\/i> to keep the team in the state of Washington. (In fact, former owner Howard Schultz \u2013 of Starbucks fame \u2013 found their conduct so egregious that he\u2019s announced plans to sue in order to regain control of the franchise.)<\/p>\n<p>Admittedly, the emails in which the Sonics owners discussed plans to move the team \u2013 even while they were publicly assuring everyone that they had no plans to move the team \u2013 are interesting. But the Scripting Guy who writes this column found the following email to be the most fascinating of all; this unedited excerpt is from an email that Sonics owner Clay Bennett sent to NBA commissioner David Stern:<\/p>\n<table id=\"EID\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" vAlign=\"top\">\n<td>\n<p class=\"lastInCell\">You are among the very few, people notwithstanding our relatively brief actual physical time together that have significantly affected my life. I view you as a role model as an extraordinarily gifted executive, a deep and compassionate thinker, and a person with a rare and unique charisma that brings out the best in everyone you touch. You are just one of my favorite people on earth and I so cherish our relationship \u2026.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>Wait a second: was that the email Clay Bennett sent to David Stern, or was that the email Ken Myer sent to the Scripting Guys asking that his script, submitted as part of the <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/games\/games08.mspx\"><b>2008 Winter Scripting Games<\/b><\/a>, be awarded full points even though the script didn\u2019t actually do what it was supposed to do?<\/p>\n<p>Of course, unlike David Stern, the Scripting Guys turn a deaf ear toward insincere flattery and fawning. Oklahoma City will likely get their basketball team, but Ken Myer did <i>not<\/i> get his Scripting Games points.<\/p>\n<p>Well, actually he did. But that\u2019s beside the point.<\/p>\n<p>At any rate, we\u2019ll keep you posted as to the Sonics whereabouts. In the meantime, there are far more important matters to attend to. Matters like what, you ask? Well, consider this. EI has a text file that includes lines like these:<\/p>\n<pre class=\"codeSample\">Location1[apples][bananas]\nLocation2[bananas][cherries]\nLocation3[apples][oranges]\nLocation4[plums][strawberries]\n<\/pre>\n<p>EI needs to extract the text found between the square brackets; that is, the fruit names. If he can do that he can then compile a list similar to this one:<\/p>\n<pre class=\"codeSample\">apples\nbananas\nbananas\ncherries\napples\noranges\nplums\nstrawberries\n<\/pre>\n<p>Unfortunately, though, he doesn\u2019t know how to extract that information, in part because there might be more than one fruit per line in the text file.<\/p>\n<p>So do the Scripting Guys have an answer for him? Well, we <i>thought<\/i> we did; without fully thinking the matter through we assumed we could use a simple regular expression to retrieve that data. That <i>almost<\/i> worked, but not quite:<\/p>\n<pre class=\"codeSample\">[apples][bananas]\n[bananas][cherries]\n[apples][oranges]\n[plums][strawberries]\n<\/pre>\n<p>How did we end up with <i>that<\/i>? Well, we initially tried searching for text found between a beginning bracket (<b>[<\/b>) and a closing bracket (<b>]<\/b>). And, if you look closely enough, you\u2019ll see that\u2019s what we got:<\/p>\n<p><b>[<\/b><i>apples][bananas<\/i><b>]<\/b><\/p>\n<p>We have a beginning bracket and a closing bracket, and all the text in between. Which \u2013 alas \u2013 happens to include another set of brackets.<\/p>\n<p>Faced with this kind of adversity, did the Scripting Guys give up? You bet we did. But a few days later we returned to the problem, and started poking around the Internet to see if anyone had solved a similar problem. Our search managed to uncover a few regular expressions that removed HTML tags from a file, but we weren\u2019t satisfied with that approach; as far as we were concerned those regular expression patterns were about as meaningful as this:<\/p>\n<pre class=\"codeSample\">^*@%@&amp;@(!(U&amp;@Y^T^&amp;R@%@R^&amp;(I@)(@()(@)I)@I(W!@!H\n<\/pre>\n<p>Which really isn\u2019t all that meaningful.<\/p>\n<p>In other words, a super-complicated regular expression search might have worked, but we decided against it. After all, we thought, there must be an easier way to get the information EI is after.<\/p>\n<p>And, as it turns out, there is:<\/p>\n<pre class=\"codeSample\">Const ForReading = 1\n\nSet objFSO = CreateObject(\"Scripting.FileSystemObject\")\nSet objFile = objFSO.OpenTextFile(\"C:\\Scripts\\Test.txt\", ForReading)\n\nstrContents = objFile.ReadAll\nobjFile.Close\n\nSet objRegEx = CreateObject(\"VBScript.RegExp\")\n\nobjRegEx.Global = True   \nobjRegEx.Pattern = \"\\[.{0,}\\]\"\n\nSet colMatches = objRegEx.Execute(strContents)  \n\nIf colMatches.Count &gt; 0 Then\n   For Each strMatch in colMatches   \n       strMatches = strMatches &amp; strMatch.Value \n   Next\nEnd If\n\nstrMatches = Replace(strMatches, \"]\", vbCrlf)\nstrMatches = Replace(strMatches, \"[\", \"\")\n\nWscript.Echo strMatches\n<\/pre>\n<p>Before we go any further we should point out that our solution is designed to work with EI\u2019s text file, which means it won\u2019t necessarily work with a similar file. For example, suppose EI had a file that looks like this, with additional text between the fruit names:<\/p>\n<pre class=\"codeSample\">Location1[apples]ABC[bananas]\nLocation2[bananas]DEF[cherries]\nLocation3[apples]GHI[oranges]\nLocation4[plums]JKL[strawberries]\n<\/pre>\n<p>Our solution won\u2019t work with this particular file, although we could easily modify it to do so. But that\u2019s another column for another day. <\/p>\n<p>As for today\u2019s column, we start things out by defining a constant named ForReading and setting the value to 1; that\u2019s the constant that tells the script which file mode (for reading) we want to use when opening the text file. And it\u2019s not long before we put that constant to use; as soon as the constant is defined we create an instance of the <b>Scripting.FileSystemObject<\/b> object, then use this line of code to open the file C:\\Scripts\\Test.txt, for reading:<\/p>\n<pre class=\"codeSample\">Set objFile = objFSO.OpenTextFile(\"C:\\Scripts\\Test.txt\", ForReading)\n<\/pre>\n<p>Once the file is open we use the <b>ReadAll<\/b> method to read in the entire contents of the file, storing that information in a variable named strContents. At that point we no longer need the file, so we call the <b>Close<\/b> method and dismiss Test.txt.<\/p>\n<p>Our next step is to create an instance of the <b>VBScript.RegExp<\/b> object, the object that enables us to use regular expressions in a VBScript script. (And yes, we <i>are<\/i> going to use a regular expression here. But it\u2019s a reasonably simple regular expression.) After we create the RegExp object we set the <b>Global<\/b> property to True, something that ensures that the script will find each instance of the target text. That brings us to this line of code:<\/p>\n<pre class=\"codeSample\">objRegEx.Pattern = \"\\[.{0,}\\]\"\n<\/pre>\n<p>As you probably know by now, the <b>Pattern<\/b> property is where we define our target text. So what exactly <i>is<\/i> our target text? Well, for starters, we\u2019re looking for a beginning bracket; that\u2019s what the <b>\\[<\/b> is for. (We need to \u201cescape\u201d the [ character by prefacing it with a \\; that\u2019s because the [ is a reserved character in a regular expression.) We don\u2019t really care too much what comes after the beginning bracket; thus we add the construction <b>.{0,}<\/b> which finds any character (and any number of characters) other than the newline character. That gives us a beginning bracket, a series of characters, and \u2013 last but not least \u2013 the ending bracket, which must also be escaped: <b>\\]<\/b>.<\/p>\n<p>After we define the Pattern we call the <b>Execute<\/b> method to carry out our regular expression search:<\/p>\n<pre class=\"codeSample\">Set colMatches = objRegEx.Execute(strContents)\n<\/pre>\n<p>When we call the Execute method, any instances of the target text that are discovered will be stored in a collection we named colMatches. If we were to echo back the value of colMatches right now we\u2019d get this:<\/p>\n<pre class=\"codeSample\">[apples][bananas]\n[bananas][cherries]\n[apples][oranges]\n[plums][strawberries]\n<\/pre>\n<p>As we already determined, that\u2019s not what we <i>want<\/i> to get back.<\/p>\n<p>Therefore, assuming that we even <i>have<\/i> some matches (that is, assuming the value of the collection\u2019s <b>Count<\/b> property is greater than 0) we execute the following For Each block:<\/p>\n<pre class=\"codeSample\">For Each strMatch in colMatches   \n    strMatches = strMatches &amp; strMatch.Value \nNext\n<\/pre>\n<p>All we\u2019re doing here is looping through the collection of matches, and appending each match to a variable named strMatches. When we\u2019ve finished looping through the collection strMatches will look like this:<\/p>\n<pre class=\"codeSample\">[apples][bananas][bananas][cherries][apples][oranges][plums][strawberries]\n<\/pre>\n<p>Does that do us any good? You bet it does. In our very next line of code, we use VBScript\u2019s <b>Replace<\/b> function to replace any instance of the closing bracket with a carriage return-linefeed (<b>vbCrLf<\/b>):<\/p>\n<pre class=\"codeSample\">strMatches = Replace(strMatches, \"]\", vbCrlf)\n<\/pre>\n<p>As soon as we do that strMatches will equal this:<\/p>\n<pre class=\"codeSample\">[apples\n[bananas\n[bananas\n[cherries\n[apples\n[oranges\n[plums\n[strawberries\n<\/pre>\n<p>And you\u2019re right: that <i>is<\/i> very close to the list we were hoping to retrieve, isn\u2019t it? In fact, all we have to do now is remove all instances of the [ character and we\u2019re home free:<\/p>\n<pre class=\"codeSample\">strMatches = Replace(strMatches, \"[\", \"\")\n<\/pre>\n<p>So <i>now<\/i> what does strMatches equal? Let\u2019s echo back the value and see for ourselves:<\/p>\n<pre class=\"codeSample\">apples\nbananas\nbananas\ncherries\napples\noranges\nplums\nstrawberries\n<\/pre>\n<p>Tah-dah! At this point EI can do whatever he wants with this list of fruits.<\/p>\n<p>That\u2019s all the time we have for today. Which is just as well; we\u2019re too nervous about the upcoming NBA vote to do much work anyway. Just for the heck of it, we decided to check out the <a href=\"http:\/\/www.okc.gov\/\" target=\"_blank\"><b>Oklahoma City home page<\/b><\/a>, in order to see what might be in store for our Sonics. Here are a few of the articles featured on the home page:<\/p>\n<table border=\"0\" cellSpacing=\"0\" cellPadding=\"0\">\n<tbody>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>City to collect ammunition, computers and tires at State Fairgrounds<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>What if my sewer backs up?<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>Be prepared this tornado season<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>Storm debris pickup complete<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>Report potholes by phone<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>&#8220;This City is Going on a Diet&#8221;<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>By comparison, here are a few of the articles we found on the home page for the city of Seattle:<\/p>\n<table border=\"0\" cellSpacing=\"0\" cellPadding=\"0\">\n<tbody>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>City encourages everyone to go out for a drive: \u201cAfter all, there\u2019s no traffic anywhere\u201d<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>Police force considers disbanding; no crimes reported since 1997<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>City Council to award all King County residents a $5,000 bonus<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>NBA teams begging for chance to move to Seattle<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" vAlign=\"top\">\u2022<\/td>\n<td class=\"listItem\">\n<p>Seattle to host tickertape parade for the Scripting Guys<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Sorry we can\u2019t provide a link to those articles; we seem to have misplaced the URL for the city of Seattle, and for all these articles. But that\u2019s OK; you can just take our word for it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! I need to parse through a text file and extract the information contained within square brackets. So far, however, I haven\u2019t been able to figure out how to do this; that\u2019s because the data isn\u2019t stored on separate lines in the file. Can you help?&#8212; EI Hey, EI. Well, today is Friday, [&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-55743","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 need to parse through a text file and extract the information contained within square brackets. So far, however, I haven\u2019t been able to figure out how to do this; that\u2019s because the data isn\u2019t stored on separate lines in the file. Can you help?&#8212; EI Hey, EI. Well, today is Friday, [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/55743","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=55743"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/55743\/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=55743"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=55743"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=55743"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}