| author | |
| committer | |
| log | c66d3f6bf6be62d565a444792390655f4db3bd7a |
| tree | 47a0e96c37a9c956419599ae11a2b6723a95a9f5 |
| parent | 84e0c148b1d276d0dd60488c095dfb395372a216 |
2 files changed, 51 insertions(+), 15 deletions(-)
lib/std/ascii.zig+44-9| ... | ... | @@ -555,22 +555,54 @@ test "ascii.endsWithIgnoreCase" { |
| 555 | 555 | try std.testing.expect(!endsWithIgnoreCase("BoB", "Bo")); |
| 556 | 556 | } |
| 557 | 557 | |
| 558 | /// Finds `substr` in `container`, ignoring case, starting at `start_index`. | |
| 559 | /// TODO boyer-moore algorithm | |
| 560 | pub fn indexOfIgnoreCasePos(container: []const u8, start_index: usize, substr: []const u8) ?usize { | |
| 561 | if (substr.len > container.len) return null; | |
| 558 | /// Finds `needle` in `haystack`, ignoring case, starting at index 0. | |
| 559 | pub fn indexOfIgnoreCase(haystack: []const u8, needle: []const u8) ?usize { | |
| 560 | return indexOfIgnoreCasePos(haystack, 0, needle); | |
| 561 | } | |
| 562 | ||
| 563 | /// Finds `needle` in `haystack`, ignoring case, starting at `start_index`. | |
| 564 | /// Uses Boyer-Moore-Horspool algorithm on large inputs; `indexOfIgnoreCasePosLinear` on small inputs. | |
| 565 | pub fn indexOfIgnoreCasePos(haystack: []const u8, start_index: usize, needle: []const u8) ?usize { | |
| 566 | if (needle.len > haystack.len) return null; | |
| 567 | if (needle.len == 0) return start_index; | |
| 568 | ||
| 569 | if (haystack.len < 52 or needle.len <= 4) | |
| 570 | return indexOfIgnoreCasePosLinear(haystack, start_index, needle); | |
| 571 | ||
| 572 | var skip_table: [256]usize = undefined; | |
| 573 | boyerMooreHorspoolPreprocessIgnoreCase(needle, skip_table[0..]); | |
| 562 | 574 | |
| 563 | 575 | var i: usize = start_index; |
| 564 | const end = container.len - substr.len; | |
| 576 | while (i <= haystack.len - needle.len) { | |
| 577 | if (eqlIgnoreCase(haystack[i .. i + needle.len], needle)) return i; | |
| 578 | i += skip_table[toLower(haystack[i + needle.len - 1])]; | |
| 579 | } | |
| 580 | ||
| 581 | return null; | |
| 582 | } | |
| 583 | ||
| 584 | /// Consider using `indexOfIgnoreCasePos` instead of this, which will automatically use a | |
| 585 | /// more sophisticated algorithm on larger inputs. | |
| 586 | pub fn indexOfIgnoreCasePosLinear(haystack: []const u8, start_index: usize, needle: []const u8) ?usize { | |
| 587 | var i: usize = start_index; | |
| 588 | const end = haystack.len - needle.len; | |
| 565 | 589 | while (i <= end) : (i += 1) { |
| 566 | if (eqlIgnoreCase(container[i .. i + substr.len], substr)) return i; | |
| 590 | if (eqlIgnoreCase(haystack[i .. i + needle.len], needle)) return i; | |
| 567 | 591 | } |
| 568 | 592 | return null; |
| 569 | 593 | } |
| 570 | 594 | |
| 571 | /// Finds `substr` in `container`, ignoring case, starting at index 0. | |
| 572 | pub fn indexOfIgnoreCase(container: []const u8, substr: []const u8) ?usize { | |
| 573 | return indexOfIgnoreCasePos(container, 0, substr); | |
| 595 | fn boyerMooreHorspoolPreprocessIgnoreCase(pattern: []const u8, table: *[256]usize) void { | |
| 596 | for (table) |*c| { | |
| 597 | c.* = pattern.len; | |
| 598 | } | |
| 599 | ||
| 600 | var i: usize = 0; | |
| 601 | // The last item is intentionally ignored and the skip size will be pattern.len. | |
| 602 | // This is the standard way Boyer-Moore-Horspool is implemented. | |
| 603 | while (i < pattern.len - 1) : (i += 1) { | |
| 604 | table[toLower(pattern[i])] = pattern.len - 1 - i; | |
| 605 | } | |
| 574 | 606 | } |
| 575 | 607 | |
| 576 | 608 | test "indexOfIgnoreCase" { |
| ... | ... | @@ -579,6 +611,9 @@ test "indexOfIgnoreCase" { |
| 579 | 611 | try std.testing.expect(indexOfIgnoreCase("foO", "Foo").? == 0); |
| 580 | 612 | try std.testing.expect(indexOfIgnoreCase("foo", "fool") == null); |
| 581 | 613 | try std.testing.expect(indexOfIgnoreCase("FOO foo", "fOo").? == 0); |
| 614 | ||
| 615 | try std.testing.expect(indexOfIgnoreCase("one two three four five six seven eight nine ten eleven", "ThReE fOUr").? == 8); | |
| 616 | try std.testing.expect(indexOfIgnoreCase("one two three four five six seven eight nine ten eleven", "Two tWo") == null); | |
| 582 | 617 | } |
| 583 | 618 | |
| 584 | 619 | /// Returns the lexicographical order of two slices. O(n). |
lib/std/mem.zig+7-6| ... | ... | @@ -1083,7 +1083,7 @@ fn boyerMooreHorspoolPreprocessReverse(pattern: []const u8, table: *[256]usize) |
| 1083 | 1083 | |
| 1084 | 1084 | var i: usize = pattern.len - 1; |
| 1085 | 1085 | // The first item is intentionally ignored and the skip size will be pattern.len. |
| 1086 | // This is the standard way boyer-moore-horspool is implemented. | |
| 1086 | // This is the standard way Boyer-Moore-Horspool is implemented. | |
| 1087 | 1087 | while (i > 0) : (i -= 1) { |
| 1088 | 1088 | table[pattern[i]] = i; |
| 1089 | 1089 | } |
| ... | ... | @@ -1096,14 +1096,15 @@ fn boyerMooreHorspoolPreprocess(pattern: []const u8, table: *[256]usize) void { |
| 1096 | 1096 | |
| 1097 | 1097 | var i: usize = 0; |
| 1098 | 1098 | // The last item is intentionally ignored and the skip size will be pattern.len. |
| 1099 | // This is the standard way boyer-moore-horspool is implemented. | |
| 1099 | // This is the standard way Boyer-Moore-Horspool is implemented. | |
| 1100 | 1100 | while (i < pattern.len - 1) : (i += 1) { |
| 1101 | 1101 | table[pattern[i]] = pattern.len - 1 - i; |
| 1102 | 1102 | } |
| 1103 | 1103 | } |
| 1104 | ||
| 1104 | 1105 | /// Find the index in a slice of a sub-slice, searching from the end backwards. |
| 1105 | 1106 | /// To start looking at a different index, slice the haystack first. |
| 1106 | /// Uses the Reverse boyer-moore-horspool algorithm on large inputs; | |
| 1107 | /// Uses the Reverse Boyer-Moore-Horspool algorithm on large inputs; | |
| 1107 | 1108 | /// `lastIndexOfLinear` on small inputs. |
| 1108 | 1109 | pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize { |
| 1109 | 1110 | if (needle.len > haystack.len) return null; |
| ... | ... | @@ -1131,7 +1132,7 @@ pub fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?us |
| 1131 | 1132 | return null; |
| 1132 | 1133 | } |
| 1133 | 1134 | |
| 1134 | /// Uses Boyer-moore-horspool algorithm on large inputs; `indexOfPosLinear` on small inputs. | |
| 1135 | /// Uses Boyer-Moore-Horspool algorithm on large inputs; `indexOfPosLinear` on small inputs. | |
| 1135 | 1136 | pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, needle: []const T) ?usize { |
| 1136 | 1137 | if (needle.len > haystack.len) return null; |
| 1137 | 1138 | if (needle.len == 0) return start_index; |
| ... | ... | @@ -1183,7 +1184,7 @@ test "indexOf" { |
| 1183 | 1184 | |
| 1184 | 1185 | test "indexOf multibyte" { |
| 1185 | 1186 | { |
| 1186 | // make haystack and needle long enough to trigger boyer-moore-horspool algorithm | |
| 1187 | // make haystack and needle long enough to trigger Boyer-Moore-Horspool algorithm | |
| 1187 | 1188 | const haystack = [1]u16{0} ** 100 ++ [_]u16{ 0xbbaa, 0xccbb, 0xddcc, 0xeedd, 0xffee, 0x00ff }; |
| 1188 | 1189 | const needle = [_]u16{ 0xbbaa, 0xccbb, 0xddcc, 0xeedd, 0xffee }; |
| 1189 | 1190 | try testing.expectEqual(indexOfPos(u16, &haystack, 0, &needle), 100); |
| ... | ... | @@ -1196,7 +1197,7 @@ test "indexOf multibyte" { |
| 1196 | 1197 | } |
| 1197 | 1198 | |
| 1198 | 1199 | { |
| 1199 | // make haystack and needle long enough to trigger boyer-moore-horspool algorithm | |
| 1200 | // make haystack and needle long enough to trigger Boyer-Moore-Horspool algorithm | |
| 1200 | 1201 | const haystack = [_]u16{ 0xbbaa, 0xccbb, 0xddcc, 0xeedd, 0xffee, 0x00ff } ++ [1]u16{0} ** 100; |
| 1201 | 1202 | const needle = [_]u16{ 0xbbaa, 0xccbb, 0xddcc, 0xeedd, 0xffee }; |
| 1202 | 1203 | try testing.expectEqual(lastIndexOf(u16, &haystack, &needle), 0); |