diff --git a/TextFilter.Test/TextFilterTests.cs b/TextFilter.Test/TextFilterTests.cs index 40ba5c6..4792ebd 100644 --- a/TextFilter.Test/TextFilterTests.cs +++ b/TextFilter.Test/TextFilterTests.cs @@ -838,4 +838,35 @@ public void RegexByWordAllFilterDropsBlankEntries() new List { "hello" }, TextFilter.Filter(["", "hello"], "hel", TextFilterType.Regex, TextFilterMatchOptions.ByWordAll).ToList()); } + + [TestMethod] + [DataRow("foo \t")] + [DataRow("foo \r\n")] + [DataRow("foo \u00a0")] + public void GlobWithNonSpaceWhitespaceDoesNotThrow(string filter) + { + // Splitting only on ' ' left a chunk of other whitespace that trimmed to an empty token, and + // the glob tokenizer then read its first character. A pasted trailing tab or newline is enough. + Assert.IsTrue(TextFilter.IsMatch("foo", filter)); + CollectionAssert.AreEqual( + new List { "foo" }, + TextFilter.Filter(["foo"], filter).ToList()); + } + + [TestMethod] + public void RegexByWordAllIgnoresNonSpaceWhitespaceBetweenWords() + { + Assert.IsTrue(TextFilter.IsMatch("hello \t world", "o", TextFilterType.Regex, TextFilterMatchOptions.ByWordAll)); + Assert.IsTrue(TextFilter.IsMatch("hello\tworld", "o", TextFilterType.Regex, TextFilterMatchOptions.ByWordAll)); + Assert.IsFalse(TextFilter.IsMatch("hello\tbye", "o", TextFilterType.Regex, TextFilterMatchOptions.ByWordAll)); + } + + [TestMethod] + [DataRow(" \t ")] + [DataRow("\r\n")] + [DataRow("\u00a0")] + public void RegexByWordAllDoesNotMatchTextOfOnlyNonSpaceWhitespace(string text) + { + Assert.IsFalse(TextFilter.IsMatch(text, "a*", TextFilterType.Regex, TextFilterMatchOptions.ByWordAll)); + } } diff --git a/TextFilter/TextFilter.cs b/TextFilter/TextFilter.cs index 201095b..16dc5dc 100644 --- a/TextFilter/TextFilter.cs +++ b/TextFilter/TextFilter.cs @@ -261,15 +261,15 @@ internal static HashSet ExtractTextTokens(string text, TextFilterMatchOp return textFilterMatchOptions switch { TextFilterMatchOptions.ByWholeString => [text], - TextFilterMatchOptions.ByWordAll => [.. text.Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim())], - TextFilterMatchOptions.ByWordAny => [.. text.Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim())], + TextFilterMatchOptions.ByWordAll => [.. text.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries)], + TextFilterMatchOptions.ByWordAny => [.. text.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries)], _ => throw new NotImplementedException($"{nameof(TextFilterMatchOptions)}.{textFilterMatchOptions} has not been implemented"), }; } internal static Dictionary> ExtractGlobFilterTokens(string filter) { - string[] filterTokens = [.. filter.Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim())]; + string[] filterTokens = [.. filter.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries)]; return filterTokens.GroupBy(t => { char prefix = t.First();