{"id":56393,"date":"2008-01-18T21:57:00","date_gmt":"2008-01-18T21:57:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2008\/01\/18\/hey-scripting-guy-how-can-i-search-for-values-in-an-excel-worksheet\/"},"modified":"2008-01-18T21:57:00","modified_gmt":"2008-01-18T21:57:00","slug":"hey-scripting-guy-how-can-i-search-for-values-in-an-excel-worksheet","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-search-for-values-in-an-excel-worksheet\/","title":{"rendered":"Hey, Scripting Guy! How Can I Search For Values in an Excel Worksheet?"},"content":{"rendered":"<p><img decoding=\"async\" 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\" \/> <\/p>\n<p>Hey, Scripting Guy! How can I use Excel\u2019s Find method to search for values within a worksheet?<\/p>\n<p>&#8212; SK<\/p>\n<p><img decoding=\"async\" height=\"5\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" border=\"0\" \/><img decoding=\"async\" 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 decoding=\"async\" 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> <\/p>\n<p>Hey, SK. Before we begin today, we have a question for you, and for everyone else out there in Scripting Land. Back when the Scripting Guys first started planning the <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/games\/default.mspx\"><b>2008 Winter Scripting Games<\/b><\/a> (February 15<sup>th<\/sup> through March 3<sup>rd<\/sup>, right here in the Script Center) we gave serious thought to adding new divisions for both IronPython and Perl. In the end, however, the Official Organizing Committee for the 2008 Winter Scripting Games unanimously voted to add only one new division: Perl.<\/p>\n<table class=\"dataTable\" id=\"EID\" cellSpacing=\"0\" cellPadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" vAlign=\"top\">\n<td class=\"\">\n<p><b>Note<\/b>. What does that mean that we \u201cunanimously voted\u201d to add only one new division? To tell you the truth, that means that Greg was in favor of adding both IronPython and Perl; in fact, he was in favor of allowing people to submit scripts in <i>any<\/i> scripting language. However, Scripting Guy Jean Ross wasn\u2019t thrilled with the idea of adding IronPython, and was only lukewarm in her support for Perl. Is that because Scripting Guy Jean Ross is a killjoy? Yes, she is. In addition to that, however, Jean also has a tendency to worry about things like how we could possibly test thousands of scripts submitted by hundreds of people and written in dozens of different scripting languages.<\/p>\n<p>Greg, by contrast, never worries about logistics or reality; he always assumes that things will magically work out. That goes not only for Scripting Games, but also for things like how to pay for his retirement.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>At any rate, we\u2019ve now had an official request to add IronPython to the 2008 Scripting Games. We\u2019re considering it, but that depends, in part, on how many people are likely to enter the IronPython division. So what do you think, guys: would you be interested in seeing IronPython added to the 2008 Scripting Games? If so, would you be interested in competing (in the Beginners and\/or the Advanced Division), or would you simply be interested in being a spectator, and having the opportunity to see what IronPython is all about? Regardless, if you have an opinion on this, drop us a line at <a href=\"mailto:scripter@microsoft.com?subject=IronPython\"><b>scripter@microsoft.com (in English, if possible)<\/b><\/a>. We\u2019ll weigh the responses we get \u2013 both pro and con \u2013 and then make a decision in the next week or so.<\/p>\n<p>Speaking of the Scripting Games (February 15<sup>th<\/sup> through March 3<sup>rd<\/sup>, right here in the Script Center) we have some <i>great<\/i> prizes to give away this year. Take a peek at <a href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/games\/games08\/prizes.mspx\"><b>this page<\/b><\/a>, and stay tuned: we hope to have a few more things to add to the list in the next week or so.<\/p>\n<p>In the meantime, we have work to do: we have to figure out how to use Microsoft Excel\u2019s Find method to search for values within a worksheet. Let\u2019s start by taking a look at a script that can find a specific value in a worksheet; we\u2019ll then take a look at a slightly different approach, but an approach that\u2019s required if we want to find a range of values. <\/p>\n<p>But first things first. The following script uses the Excel <b>Find<\/b> method to locate all the cells in a spreadsheet that have a <b>Value<\/b> equal to 4:<\/p>\n<pre class=\"codeSample\">Const xlValues = -4163\n\nSet objExcel = CreateObject(\"Excel.Application\")\nobjExcel.Visible = True\n\nSet objWorkbook = objExcel.Workbooks.Open(\"C:\\Scripts\\Test.xls\")\nSet objWorksheet = objWorkbook.Worksheets(\"Sheet1\")\n\nSet objRange = objWorksheet.UsedRange\n\nSet objTarget = objRange.Find(4)\n\nIf Not objTarget Is Nothing Then\n    Wscript.Echo objTarget.AddressLocal(False,False)\n    strFirstAddress = objTarget.AddressLocal(False,False)\nEnd If\n\nDo Until (objTarget Is Nothing)\n    Set objTarget = objRange.FindNext(objTarget)\n\n    strHolder = objTarget.AddressLocal(False,False)\n    If strHolder = strFirstAddress Then\n        Exit Do\n    End If\n\n    Wscript.Echo objTarget.AddressLocal(False,False)\nLoop\n<\/pre>\n<p>As you can see, we start out by defining an constant named xlValues, setting the value of this constant to -4163. (Which, by amazing coincidence, is Scripting Guy Dean Tsaltas\u2019 favorite number.) We create an instance of the <b>Excel.Application<\/b> object, set the <b>Visible<\/b> property to True, then use the following two lines of code to open the file C:\\Scripts\\Test.xls and bind to the first worksheet in that file:<\/p>\n<pre class=\"codeSample\">Set objWorkbook = objExcel.Workbooks.Open(\"C:\\Scripts\\Test.xls\")\nSet objWorksheet = objWorkbook.Worksheets(\"Sheet1\")\n<\/pre>\n<p>As it turns out, the Find method actually belongs to Excel\u2019s <b>Range<\/b> object; that means we have to define a range before we can call the Find method. Because we want to search the entire worksheet, we create a range that\u2019s equal to the worksheet\u2019s <b>UsedRange<\/b> property:<\/p>\n<pre class=\"codeSample\">Set objRange = objWorksheet.UsedRange\n<\/pre>\n<p>In effect, that selects the range of cells that actually contain data. For example, if you have data in cell A1 and data in cell G11, the UsedRange consists of cell A1, cell G11, and all the cells in between.<\/p>\n<p>After we define a range we can then search for the first instance of our target value (4) by executing this line of code:<\/p>\n<pre class=\"codeSample\">Set objTarget = objRange.Find(4)\n<\/pre>\n<p>In its simplest form (and we won\u2019t talk about the more complicated forms, at least not today), the Find method requires only a single parameter: the value being searched for. Specify the target value, and the Find method will hunt down the first cell that meets that criteria.<\/p>\n<p>So how do we know which cell <i>is<\/i> the first cell that met our search criteria? The easiest way to do that is to check and see if the object reference objTarget is equal to Nothing:<\/p>\n<pre class=\"codeSample\">If Not objTarget Is Nothing Then\n<\/pre>\n<p>If it <i>is<\/i> (that is, if objTarget is not a valid object reference) that means our search came up empty; in that case, the script simply ends. On the other hand, if objTarget <i>is<\/i> a valid object reference then we execute these two lines of code:<\/p>\n<pre class=\"codeSample\">Wscript.Echo objTarget.AddressLocal(False,False)\nstrFirstAddress = objTarget.AddressLocal(False,False)\n<\/pre>\n<p>In the first line we\u2019re simply echoing back the value of the <b>AddressLocal<\/b> property. Why AddressLocal as opposed to the Address property? Well, the Address property returns cell addresses that look like this:<\/p>\n<pre class=\"codeSample\">$A$2\n$B$2\n$C$2\n<\/pre>\n<p>By contrast, AddressLocal (provided you set the row and column parameters to False, like we did in our example) returns cell addresses that look like this:<\/p>\n<pre class=\"codeSample\">A2\nB2\nC2\n<\/pre>\n<p>We like the latter style a little better.<\/p>\n<table class=\"dataTable\" id=\"EIG\" 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>. The AddressLocal property lets you return cell addresses in all sorts of different ways: $A$1; $A1; A1; etc. For more information, take a peek at the <a href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/aa174750(office.11).aspx\" target=\"_blank\"><b>Excel VBA Language Reference<\/b><\/a> on MSDN.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>After echoing back the value of the AddressLocal property, we then assign that same value to a variable named strFirstAddress:<\/p>\n<pre class=\"codeSample\">strFirstAddress = objTarget.AddressLocal(False,False)\n<\/pre>\n<p>Why do we do that? We actually have a good reason for that: the Find method is a little quirky. (And, trust us, the Scripting Guy who writes this column knows quirky when he sees it.) For one thing, the Find method finds only one instance of the target value at a time; as you\u2019re about to see, to find additional instances of the target value you need to call the <b>FindNext<\/b> method \u2026 repeatedly.<\/p>\n<p>Oh, and that\u2019s not all. On top of that, the Find and FindNext methods don\u2019t know when to quit. Suppose we put the FindNext method in a loop and ask it to find all the remaining instances of the target value. (Which is exactly what we\u2019re going to do.) Then suppose FindNext locates all the values. Will it stop at that point? Nope. Instead, it loops back to the beginning of the range and begins finding the same values over and over again. <\/p>\n<p>That means that we need a way to tell FindNext, \u201cHey, it\u2019s time to stop; you already <i>found<\/i> this particular value.\u201d One way to do that is to store the address of the first target value in the variable strFirstAddress. Each time FindNext finds an instance of the target value we\u2019ll check that address against the address stored in strFirstAdrress. If they match, that means that we\u2019ve searched the entire worksheet and it\u2019s time to quit.<\/p>\n<p>Speaking of putting the FindNext method in a loop, that\u2019s what this block of code is for:<\/p>\n<pre class=\"codeSample\">Do Until (objTarget Is Nothing)\n    Set objTarget = objRange.FindNext(objTarget)\n\n    strHolder = objTarget.AddressLocal(False,False)\n    If strHolder = strFirstAddress Then\n        Exit Do\n    End If\n\n    Wscript.Echo objTarget.AddressLocal(False,False)\nLoop\n<\/pre>\n<p>What we\u2019ve done here is configure a Do loop that runs until objTarget is no longer a valid reference; when that happens it means that we were unable to find another instance of the target value. Inside the loop we call the following line of code to find the next target value:<\/p>\n<pre class=\"codeSample\">Set objTarget = objRange.FindNext(objTarget)\n<\/pre>\n<p>Come to think of it, this is also a bit quirky, isn\u2019t it? Although the code looks kind of weird, all we\u2019re doing here is calling FindNext and passing it a single parameter: objTarget, the object reference to the cell we found using the Find method. This parameter tells FindNext where to start searching; having found the first cell containing the target value we now want to pick up the search from that point. Admittedly, it looks like we\u2019re asking FindNext to find the object reference objTarget. But looks can be deceiving: we\u2019re just telling FindNext where to start from.<\/p>\n<p>So then what happens after we call FindNext? Well, FindNext will find the next cell that meets our search criteria. When that happens, we grab the value of the AddressLocal property and store it in a variable named strHolder:<\/p>\n<pre class=\"codeSample\">strHolder = objTarget.AddressLocal(False,False)\n<\/pre>\n<p>We then check to see if strHolder and strFirstAddress are equivalent:<\/p>\n<pre class=\"codeSample\">If strHolder = strFirstAddress Then\n<\/pre>\n<p>If they are, that means we\u2019ve found everything there is to find. In turn, we call the <b>Exit Do<\/b> statement and exit both the loop and the script. If the two variables <i>aren\u2019t<\/i> equivalent then we echo back the value of the AddressLocal property, then head back to the top of the loop and try again.<\/p>\n<p>Now, like we said, that works fine (and works pretty darn fast, even on large spreadsheets), <i>provided<\/i> you\u2019re searching for a single value: a number, a string, a date, whatever. For better or worse, however, the Find method can\u2019t work with a range of values: if you need to find all the cells with a value less than 5, well, Find isn\u2019t going to do it. Instead, you have to use a script like this one, a script that individually looks at each and every cell in the range:<\/p>\n<pre class=\"codeSample\">Const xlValues = -4163\n\nSet objExcel = CreateObject(\"Excel.Application\")\nobjExcel.Visible = True\n\nSet objWorkbook = objExcel.Workbooks.Open(\"C:\\Scripts\\Test.xls\")\nSet objWorksheet = objWorkbook.Worksheets(\"Sheet1\")\n\nSet objRange = objWorksheet.UsedRange\n\nFor Each objCell in objRange.Cells\n    If objCell.Value &lt; 5 Then\n        Wscript.Echo objCell.AddressLocal(False,False)\n    End If\nNext\n<\/pre>\n<p>As you can see, after creating our Range object we set up a For Each loop to loop through each cell in that range:<\/p>\n<pre class=\"codeSample\">For Each objCell in objRange.Cells\n<\/pre>\n<p>For each of these cells we check to see if the Value is less than 5; if it is, then we echo back the cell\u2019s AddressLocal property. From there we loop around and check the next cell in the collection. It\u2019s a little slower than using the Find method, but it\u2019s the only way that we know of to look for a range of values.<\/p>\n<p>And there you have it, SK; we hope that helps. By the way, we have another question for everyone: how much interest would there be if we charged everyone $20 to enter the Scripting Games, with all the money going to the Scripting Guys Vacation and Boondoggle Fund? If you like <i>that<\/i> idea just send an email to \u2013 well, never mind. You-know-who probably won\u2019t let us do <i>that<\/i> either. In addition to logistics and reality, she has the annoying habit of worrying about whether or not things are legal.<\/p>\n<p>Killjoy.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! How can I use Excel\u2019s Find method to search for values within a worksheet? &#8212; SK Hey, SK. Before we begin today, we have a question for you, and for everyone else out there in Scripting Land. Back when the Scripting Guys first started planning the 2008 Winter Scripting Games (February 15th [&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":[710,48,49,3,5],"class_list":["post-56393","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-excel-spreadsheet","tag-microsoft-excel","tag-office","tag-scripting-guy","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! How can I use Excel\u2019s Find method to search for values within a worksheet? &#8212; SK Hey, SK. Before we begin today, we have a question for you, and for everyone else out there in Scripting Land. Back when the Scripting Guys first started planning the 2008 Winter Scripting Games (February 15th [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/56393","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=56393"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/56393\/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=56393"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=56393"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=56393"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}