Normal quotes
This commit is contained in:
parent
5e10794a24
commit
18011c595a
352 changed files with 6040 additions and 6040 deletions
50
14-02.md
50
14-02.md
|
|
@ -5,7 +5,7 @@
|
|||
### The Boyer-Moore Algorithm {#Heading4}
|
||||
|
||||
All our *a priori* knowledge of string searching is stated above, but
|
||||
there’s another sort of knowledge—knowledge that’s generated
|
||||
there's another sort of knowledge—knowledge that's generated
|
||||
dynamically. As we search through the buffer, we acquire information
|
||||
each time we check for a match. One sort of information that we acquire
|
||||
is based on partial matches; we can often skip ahead after partial
|
||||
|
|
@ -14,23 +14,23 @@ already implicitly done a comparison of the partially matched buffer
|
|||
characters with all possible pattern start locations that overlap those
|
||||
partially-matched bytes.
|
||||
|
||||
If that makes your head hurt, it should—and don’t worry. This line of
|
||||
If that makes your head hurt, it should—and don't worry. This line of
|
||||
thinking, which is the basis of the Knuth-Morris-Pratt algorithm and
|
||||
half the basis of the Boyer-Moore algorithm, is what gives Boyer-Moore
|
||||
its reputation for inscrutability. That reputation is well deserved for
|
||||
this aspect (which I will not discuss further in this book), but there’s
|
||||
another part of Boyer-Moore that’s easily understood, easily
|
||||
this aspect (which I will not discuss further in this book), but there's
|
||||
another part of Boyer-Moore that's easily understood, easily
|
||||
implemented, and highly effective.
|
||||
|
||||
Consider this: We’re searching for the pattern “ABC,” beginning the
|
||||
search at the start (offset 0) of a buffer containing “ABZABC.” We match
|
||||
on ‘A,’ we match on ‘B,’ and we mismatch on ‘C’; the buffer contains a
|
||||
‘Z’ in this position. What have we learned? Why, we’ve learned not only
|
||||
that the pattern doesn’t match the buffer starting at offset 0, but also
|
||||
that it can’t possibly match starting at offset 1 or offset 2, either!
|
||||
After all, there’s a ‘Z’ in the buffer at offset 2; since the pattern
|
||||
doesn’t contain a single ‘Z,’ there’s no way that the pattern can match
|
||||
starting at *any* location from which it would span the ‘Z’ at offset 2.
|
||||
Consider this: We're searching for the pattern "ABC," beginning the
|
||||
search at the start (offset 0) of a buffer containing "ABZABC." We match
|
||||
on ‘A,' we match on ‘B,' and we mismatch on ‘C'; the buffer contains a
|
||||
‘Z' in this position. What have we learned? Why, we've learned not only
|
||||
that the pattern doesn't match the buffer starting at offset 0, but also
|
||||
that it can't possibly match starting at offset 1 or offset 2, either!
|
||||
After all, there's a ‘Z' in the buffer at offset 2; since the pattern
|
||||
doesn't contain a single ‘Z,' there's no way that the pattern can match
|
||||
starting at *any* location from which it would span the ‘Z' at offset 2.
|
||||
We can just skip straight from offset 0 to offset 3 and continue, saving
|
||||
ourselves two comparisons.
|
||||
|
||||
|
|
@ -41,8 +41,8 @@ Look at it differently, though: What if we compare the pattern starting
|
|||
with the last (rightmost) byte, rather than the first (leftmost) byte?
|
||||
In other words, what if we compare from high memory toward low, in the
|
||||
direction in which string instructions go after the **STD** instruction?
|
||||
After all, we’re comparing one set of bytes (the pattern) to another set
|
||||
of bytes (a portion of the buffer); it doesn’t matter in the least in
|
||||
After all, we're comparing one set of bytes (the pattern) to another set
|
||||
of bytes (a portion of the buffer); it doesn't matter in the least in
|
||||
what order we compare them, so long as all the bytes in one set are
|
||||
compared to the corresponding bytes in the other set.
|
||||
|
||||
|
|
@ -51,25 +51,25 @@ compared to the corresponding bytes in the other set.
|
|||
------------------- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
We learn nothing new from a mismatch on the leftmost character, except
|
||||
that the pattern can’t match starting at that location. A mismatch on
|
||||
that the pattern can't match starting at that location. A mismatch on
|
||||
the rightmost character, however, tells us about the possibilities of
|
||||
the pattern matching starting at every buffer location from which the
|
||||
pattern spans the mismatch location. If the mismatched character in the
|
||||
buffer doesn’t appear in the pattern, then we’ve just eliminated not one
|
||||
buffer doesn't appear in the pattern, then we've just eliminated not one
|
||||
potential match, but as many potential matches as there are characters
|
||||
in the pattern; that’s how many locations there are in the buffer that
|
||||
in the pattern; that's how many locations there are in the buffer that
|
||||
*might* have matched, but have just been shown not to, because they
|
||||
overlap the mismatched character that doesn’t belong in the pattern. In
|
||||
overlap the mismatched character that doesn't belong in the pattern. In
|
||||
this case, we can skip ahead by the full pattern length in the buffer!
|
||||
This is how we can outperform even **REPNZ SCASB; REPNZ SCASB** has to
|
||||
check every byte in the buffer, but Boyer-Moore doesn’t.
|
||||
check every byte in the buffer, but Boyer-Moore doesn't.
|
||||
|
||||
Figure 14.1 illustrates the operation of a Boyer-Moore search when the
|
||||
rightcharacter of the search pattern (which is the first character
|
||||
that’s compared at each location because we’re comparing backwards)
|
||||
that's compared at each location because we're comparing backwards)
|
||||
mismatches with a buffer character that appears nowhere in the pattern.
|
||||
Figure 14.2 illustrates the operation of a partial match when the
|
||||
mismatch occurs with a character that’s not a pattern member. In this
|
||||
mismatch occurs with a character that's not a pattern member. In this
|
||||
case, we can only skip ahead past the mismatch location, resulting in an
|
||||
advance of fewer bytes than the pattern length, and potentially as
|
||||
little as the same single byte distance by which the standard search
|
||||
|
|
@ -79,7 +79,7 @@ approach advances.
|
|||
**Figure 14.1** *Mismatch on first character checked.*
|
||||
|
||||
What if the mismatch occurs with a buffer character that *does* occur in
|
||||
the pattern? Then we can’t skip past the mismatch location, but we can
|
||||
the pattern? Then we can't skip past the mismatch location, but we can
|
||||
skip to whatever location aligns the rightmost occurrence of that
|
||||
character in the pattern with the mismatch location, as shown in Figure
|
||||
14.3.
|
||||
|
|
@ -91,9 +91,9 @@ a mismatch, we see what we can learn from the buffer character that
|
|||
failed to match the pattern. Imagine that we move the pattern to the
|
||||
right across the mismatch location until we find a start location that
|
||||
the mismatch does not eliminate as a possible match for the pattern. If
|
||||
the mismatch character doesn’t appear in the pattern, the pattern can
|
||||
the mismatch character doesn't appear in the pattern, the pattern can
|
||||
move clear past the mismatch location. Otherwise, the pattern moves
|
||||
until a matching pattern byte lies atop the mismatch. That’s all there
|
||||
until a matching pattern byte lies atop the mismatch. That's all there
|
||||
is to it!
|
||||
|
||||
\
|
||||
|
|
|
|||
Loading…
Reference in a new issue