0

I have to find whether the String Contains one of the Exact word which are present in the List. Eg:

List<string> KeyWords = new List<string>(){"Test","Re Test","ACK"};
String s1 = "Please give the Test"
String s2 = "Please give Re Test"
String s3 = "Acknowledge my work"

Now, When I use: Keywords.Where(x=>x.Contains(s1)) It Gives me a Match which is correct. But for s3 it should not.

Any workaround for this.

5 Answers5

0

Use split function on the basis of space and match the words. i hope that will worked.

  • I had the Same Idea but the Strings in the List to have Spaces in them. Eg: Re Test. So when I split that on the Basis of Spaces Re and Test will be considered as 2 Different Words. – Ajay Upadhyaya Aug 26 '21 at 07:27
  • So does that matter ? Like Re and Test will be treated as separate words but check String s2 = "Please give Re Test" its also have sepration between then secondly as per your logic one words match it will return true then test matches with the list first word. Normally we use single words in list to matching. – Jawad Rafiq Aug 26 '21 at 07:33
  • `Re Test` is also a subset of `Test` - Re Test won't match anything that Test doesn't match first, so it can be ignored. – pavlindrom Aug 26 '21 at 12:38
0

How about using regular expressions?

public static class Program
{
    public static void Main(string[] args)
    {
        var keywords = new List<string>() { "Test", "Re Test", "ACK" };
        var targets = new[] {
            "Please give the Test",
            "Please give Re Test",
            "Acknowledge my work"
        };

        foreach (var target in targets)
        {
            Console.WriteLine($"{target}: {AnyMatches(target, keywords)}");
        }

        Console.ReadKey();
    }

    private static bool AnyMatches(string target, IEnumerable<string> keywords)
    {
        foreach (var keyword in keywords)
        {
            var regex = new Regex($"\\b{Regex.Escape(keyword)}\\b", RegexOptions.IgnoreCase);

            if (regex.IsMatch(target))
                return true;
        }

        return false;
    }
}

Creating the regular expression always on-the-fly is maybe not the best option in production, so you should think of creating a list of Regex based on your keywords instead of storing only the keywords in a dumb string list.

Oliver
  • 43,366
  • 8
  • 94
  • 151
0

Your usage of Contains is backwards:

var foundKW = KeyWords.Where(kw => s1.Contains(kw)).ToList();
Spencer Bench
  • 647
  • 4
  • 7
  • 1
    This is much better than any of the suggested RegEx solutions. And faster too! – pavlindrom Aug 26 '21 at 12:35
  • How is this passing scenario 3? – vsarunov Aug 26 '21 at 13:27
  • @vsarunov Good catch! I updated the answer. – Spencer Bench Aug 26 '21 at 18:24
  • 1
    This update still does not resolve case 3. You have a full word to match. your answer will return `Acknowledge` Match on `ACK` – vsarunov Aug 26 '21 at 19:22
  • @vsarunov Re-read the OP. All they say is that `s3` shouldn't get a match. (The code should say that `"Acknowledge my work"` doesn't contain `"ACK"`.) The case-sensitive version of my answer meets that criteria, so I changed it back. – Spencer Bench Aug 26 '21 at 19:42
  • 1
    And if the supplied string is "ACKnowledge my work" ? This is not about case sensitive, your solution should be regardless of it. Providing something that works does not mean it is correct per say. – vsarunov Aug 27 '21 at 08:11
  • @vsarunov OP hasn't provided enough information or context for us to determine the correct behavior for "ACKnowledge my work". Nor do we have enough information to say whether the solution should be case sensitive. – Spencer Bench Aug 27 '21 at 16:45
  • How about this to solve all cases, and do it case insensitive? `var foundKW = KeyWords.Any(kw => s1.Contains(kw, StringComparer.CurrentCultureIgnoreCase));` - I didn't test it, but if it's good, can you edit the answer with this? – pavlindrom Sep 01 '21 at 21:00
  • @pavlindrom That would result in `"ACK"` matching `"Acknowledge my work"` (`s3`), but OP explicitly stated that `s3` shouldn't match any of the keywords. – Spencer Bench Sep 01 '21 at 21:35
0

Bit different solution.

void Main()
{
    var KeyWords = new List<string>(){ "Test","Re Test","ACK" };
    
    var array = new string[] {
        "Please give the Test",
        "Please give Re Test",
        "Acknowledge my work"
    };
            
    foreach(var c in array)
    {
        Contains(c,KeyWords); // Your result.
    }
}

private bool Contains(string sentence, List<string> keywords) {
        var result = keywords.Select(keyWord=>{
            var parts3 = Regex.Split(sentence, keyWord, RegexOptions.IgnoreCase).Where(x=>!string.IsNullOrWhiteSpace(x)).First().Split((char[])null); // Split by the keywords and get the rest of the words splitted by empty space
            var splitted = sentence.Split((char[])null); // split the original string.
            
            return parts3.Where(t=>!string.IsNullOrWhiteSpace(t)).All(x=>splitted.Any(t=>t.Trim().Equals(x.Trim(),StringComparison.InvariantCultureIgnoreCase)));
        }); // Check if all remaining words from parts3 are inside the existing splitted string, thus verifying if full words.
        return result.All(x=>x);// if everything matches then it was a match on full word.
}

The Idea is to split by the word you are looking for e.g Split by ACK and then see if the remaining words are matched by words splitted inside the original string, if the remaining match that means there was a word match and thus a true. If it is a part split meaning a sub string was taken out, then words wont match and thus result will be false.

vsarunov
  • 1,433
  • 14
  • 26
-2

how about the using of regex

using \bthe\b, \b represents a word boundary delimiter.

List<string> KeyWords = new List<string>(){"Test","Re Test","ACK"};
String s1 = "Please give the Test"
String s2 = "Please give Re Test"
String s3 = "Acknowledge my work"
bool result = false ;
foreach(string str in KeyWords)
    {
      result = Regex.IsMatch(s1 , @"\b"+str +"\b"); 
      if(result)
         break; 
    }

 
Tahir Rehman
  • 332
  • 2
  • 9