检查字符串是否包含一组子字符串并保存匹配的子字符串

10

我的情况是:我有一个代表文本的字符串。

string myText = "Text to analyze for words, bar, foo";   

还有一个要在其中搜索的单词列表

List<string> words = new List<string> {"foo", "bar", "xyz"};

如果有的话,我想知道获取文本中包含的单词列表最有效的方法,就像这样:

List<string> matches = myText.findWords(words)

在CPU时间或内存方面高效吗? - adv12
myText的大小是多少,你将进行多少次搜索操作? - npinti
你需要定义一下你所说的“单词”是什么意思。比如在字符串“This is foobar”中,“foo”应该被匹配吗?使用Contains方法可以匹配,而使用Split方法则不能。 - juharr
5个回答

9

这个查询没有特别的分析,除了你需要使用Contains方法。所以你可以尝试这样做:

string myText = "Text to analyze for words, bar, foo";

List<string> words = new List<string> { "foo", "bar", "xyz" };

var result = words.Where(i => myText.Contains(i)).ToList();
//result: bar, foo

考虑到编码时间的效率(这一点不应被忽视),这可能是最佳选择。 - Drew Kennedy
@DrewKennedy 如果问题不复杂,为什么不选择最简单和紧凑的解决方案呢? - Hossein Narimani Rad
@HosseinNarimaniRad 我同意这并不重要。我认为评论指的是这种方法需要多次遍历字符串,这是不必要的。此外,如果单词相对较长,Boyer-Moore-Horspool算法可以显着加速算法。 - Bas
@Bas 谢谢。我将要检查 Boyer-Moore-Horspool 算法。 - Hossein Narimani Rad
@HosseinNamariRad,针对 'This is foo. This is foo?'这个问题,也许使用正则表达式中的 \b 可以帮助解决该问题。 - Bas
显示剩余2条评论

5
您可以使用一个 HashSet<string> 并交集两个集合:
string myText = "Text to analyze for words, bar, foo"; 
string[] splitWords = myText.Split(' ', ',');

HashSet<string> hashWords = new HashSet<string>(splitWords,
                                                StringComparer.OrdinalIgnoreCase);
HashSet<string> words = new HashSet<string>(new[] { "foo", "bar" },
                                            StringComparer.OrdinalIgnoreCase);

hashWords.IntersectWith(words);

1
虽然这个处理方式可以处理给定的例子,但是它无法处理像“Here is foo! Where is bar? I am xyz.”这样的字符串。基本上,你需要在任何可以分隔单词的地方进行拆分。此外,原帖并没有提到是否应该在像“This is foobar”这样的字符串中匹配“foo”。 - juharr
@juharr 这是使用 HashSet 的示例,OP 可以在任何分隔符上拆分。他还可以在将字符串插入集合之前修剪它们,但我没有这样做。 - Yuval Itzchakov
我完全同意,如果OP想查看单词而不仅仅是任何子字符串,这是正确的方法。 我只是认为应该指出拆分过程可能会更加复杂。 - juharr

3

一个正则表达式的解决方案

var words = new string[]{"Lucy", "play", "soccer"};
var text = "Lucy loves going to the field and play soccer with her friend";
var match = new Regex(String.Join("|",words)).Match(text);
var result = new List<string>();

while (match.Success) {
    result.Add(match.Value);
    match = match.NextMatch();
}

//Result ["Lucy", "play", "soccer"]

你应该使用Regex.Escape。 - mrwaim

0

如果你想使用myText.findWords(words),你可以创建一个扩展方法来实现这个功能,它可以作为String类的一个扩展。

public static class StringExtentions
{
    public static List<string> findWords(this string str, List<string> words)
    {
        return words.Where(str.Contains).ToList();
    }
}

使用方法:

string myText = "Text to analyze for words, bar, foo";
List<string> words = new List<string> { "foo", "bar", "xyz" };
List<string> matches = myText.findWords(words);
Console.WriteLine(String.Join(", ", matches.ToArray()));
Console.ReadLine();

结果:

foo,bar


0

这是一个简单的解决方案,考虑了空格和标点符号:

static void Main(string[] args)
{
    string sentence = "Text to analyze for words, bar, foo";            
    var words = Regex.Split(sentence, @"\W+");
    var searchWords = new List<string> { "foo", "bar", "xyz" };
    var foundWords = words.Intersect(searchWords);

    foreach (var item in foundWords)
    {
        Console.WriteLine(item);
    }

    Console.ReadLine();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接