Searching

Sorting's easy; there's a function for it. Searching a list for a particular element—or for a part of an element—isn't quite so straightforward. Searching is one of those things where there is definitely more than one way to do it. Given a list of strings and a search string, you could, for example, simply iterate over the list with a foreach loop and test each element against the string, like this:

chomp($key = <STDIN>);  # thing to look for
foreach $el (@strings) {
   if ($key eq $el) {
      $found = 1;
   }
}

If the thing you were searching for can be a substring of an element in the list, you could use the index function to search for the substring in the string. The index function returns the position of the substring in the string, if it's found, and -1 otherwise (remember that string positions, like arrays, start from 0):

foreach $el (@strings) {
   if ((index $el, $key) >= 0) {   # -1 means not found
      $found = 1;
   }
}

A more efficient (and potentially more powerful) version of the substring tests would be to use patterns, which you'll learn more about tomorrow (don't worry about this syntax right now):

foreach $el (@strings) {
   if ($el =~ /$key/) {
      $found = 1;
   }
}

Despite the differences with the test, all these examples use a number of lines of code. To make things even more efficient, number-of-characters-wise, we can use Perl's built-in grep function. Named after the Unix tool of the same name, grep is used specifically for searching for things in lists. As with many other Perl features, however, grep behaves differently when used either in a list or a scalar context.

In list context, grep is used to extract all the elements of a list for which an expression or test is true, and return a new list of those elements. So, for example, here's an example of grep that will extract all the elements of the list @nums that are greater than 100:

@large = grep { $_ > 100 }  @nums;

Note the use of our friend the $_ default variable. The grep function works by taking each element in the list and assigning it to $_, and then evaluating the expression inside the brackets. If the expression is true, that list element “matches” the search and is added to the final list. Otherwise, grep moves onto the next element in the @nums list until it gets to the end.

You can use any expression you want to inside the brackets. The expression you use, however, should be a test that returns true or false, so that grep can build the new list on that criteria.

An alternate way to use grep is with a pattern built using a regular expression. We'll learn all about regular expressions tomorrow and the next day, but I'll include an example here (and in the example that follows this section), just to give you a taste:

@exes = grep /x/, @words;

Instead of a test inside of curly brackets, as with the previous examples, this example uses a pattern. The characters inside the slashes (here, just the character x) are the search pattern; in this case, grep will find all the elements in the @words array that contain the letter x, and store those words in the @exes array. You can also use a variable inside the search pattern:

print "Search for? ";
chomp($key = <STDIN>);
@exes = grep /$key/, @words;

The pattern inside the slashes can be any number of characters, and grep will search for that set of characters in any element in the list. So, for example, a pattern of /the/ will match any elements that contain the letters the (which includes the word “the” as well as the words “there” or “other”). As you'll learn tomorrow, the pattern can also contain a number of special characters to build much more sophisticated search criteria. Don't forget the comma after the pattern; unlike the syntax with an expression inside brackets, the comma is required after the pattern.

In scalar context, grep behaves much the same as in list context, except that instead of returning a list of all the elements that matched, grep returns the number of elements that matched (0 means no matches).

The grep function works best with lists or arrays, but there's nothing stopping you from using it with hashes, as long as you write your test correctly. For example, this bit of code uses grep to find all the hash keys for which either the key or its associated value is larger than 100:

@largekeys = grep { $_ > 100 or $numhash{$_}  > 100 }  keys %numhash;

In the previous lesson's webbuild.pl example, there was a huge ifelsif construct that was used to determine whether a color entered by the user was valid. Using the grep function, it would be more easily written as:

elsif (grep { $in eq $_ }  ("white", "black", "red", ...))

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.235.144