Home > Software design >  Is it possible to use a list as a pattern when searching for matches?
Is it possible to use a list as a pattern when searching for matches?

Time:05-01

I basically have criminals with different variables that are added to a report and it looks something like this:

reports.Add(new Report(tbxCriminalSuspicion.Text, 
   (new Criminal(Ordformatering(tbxName.Text), Ordformatering(tbxSex.Text), int.Parse(tbxAge.Text),
   double.Parse(tbxHeight.Text), Ordformatering(tbxHairColor.Text)))));

Then I create another string that I want to use to search between the criminals. You type into a textbox and it is placed into a list by:

string allSearchWords = tbxSearchWords.text;
List<string> splitSearchWords = new List<string>();
allSearchWords = allSearchWords.Replace(" ", "");
splitSearchWords = allSearchWords.Split(',').ToList();

Now I've got a list of words and I'm able to search my criminals via:

splitSearchWords.All((criminal).Contains);

However, in the case of the situation looking as:

Criminal 1: 18 years old, 176 cm

Criminal 2: 34 years old, 180 cm

Both criminals will show up in the Listbox even though only one is 18 years old. In other words, is it possible to search for an exact match using a list as a pattern? Can attach some code.

List<Report> reports = new List<Report>();
List<string> splitSearchWords = new List<string>();

        private void btnSearch_Click(object sender, EventArgs e)
        {
            lbxLista.Items.Clear();

            if (string.IsNullOrWhiteSpace(tbxSearchWords.Text))
            {
                MessageBox.Show("Vänligen fyll i dina sökord innan du söker enligt \"Sökord, sökord, sökord, ...\"",
                        "Felinmatning", MessageBoxButtons.OK, MessageBoxIcon.Information);
                     //Just a check so that the searchbox isn't empty!!!!
            }

            else
            {
                string allSearchWords = tbxSearchWords.Text;
                allSearshWords = allSearshWords.Replace(" ", "");
                splitSearchWords = allSearchWords.Split(',').ToList();

                for (int i = 0; i < reports.Count; i  )
                {
                    if(ContainsSearchWord(reports[i].GetData(), splitSearchWords))
                    {
                        lbxLista.Items.Add(reports[i].ToString());
                    }
                }
            }
        }

        public static bool ContainsSearchWord(string stringToTest, List<string> searchedWords)
        {
            return searchedWords.All((stringToTest).Contains);
        }

The Classes, Report and Criminal:

class Report
    {
        public string GetData()
        {
            return ""   criminal.criminalName   " "   criminal.criminalSex  
                " "   criminal.criminalAge   " "  
                criminal.criminalHeight   " "   criminal.criminalHairColor;
        }
    }

class Criminal
    {
        private string privatCriminalName;
        private string privatCriminalSex;
        private int privatCriminalAge;
        private double privatCriminalHeight;
        private string privatCriminalHairColor;

        public Criminal(string mCriminalName, string mCriminalSex,
            int mCriminalAge, double mCriminalHeight, string mCriminalHeightColor)
        {
            this.criminalName = mCriminalName;
            this.criminalSex = mCriminalSex;
            this.criminalAge = mCriminalAge;
            this.criminalHeight = mCriminalHeight;
            this.criminalHairColor = mCriminalHeightColor;
        }
        //Then I have properties to access these from outside the class but removed due to being messy and lengthy in post.
    }

Layout of the program, ANMÄLAN is where you enter to register a crime, SÖK is where you search for reports and SÖKRESULTAT is where the matching reports will shop up

Pardon the long post, after 10 hours I'm just lost.

CodePudding user response:

Instead of using a string to test the pattern, you can use an array. This array would contain each of the traits and the crime as separate string values. This way, you can still use Contains, but it will individually test the strings, instead of their substrings.

public static bool ContainsSearchWord(string stringToTest, List<string> searchedWords) {
        return searchedWords.All((stringToTest.Split(' ')).Contains);
}

You don't even have to create a variable for this, just use Split() on what you already have.

CodePudding user response:

is it possible to search for an exact match using a list as a pattern?

Taking a bit of a stab in the dark here but if you have these strings:

criminals = new string[] {
  "Criminal 1: 18 years old, 176 cm",
  "Criminal 2: 34 years old, 180 cm"
}

And the user types this as their search term:

18,old

And you want to make sure the "18" doesn't match 180 in the height of Criminal 2, then you can use a regular expression:

var searchTerms = "18,old".Split(',').Select(s => $@"\b{s}\b").ToArray();


criminals.Where(c => searchTerms.All(st => Regex.IsMatch(c, st)));

This will return only criminal where the string matches all the regular expressions.

Critically, your searchTerms have become an array like:

new string[] { @"\b18\b", @"\bold\b" };

The \b means "word boundary" - a zero-width character between a "non word character" like a space, punctuation, end/start of string etc, and the word character you're looking for

Thus \b18\b will match "he is 18 years old" and "it is 18", but it will not match "it is 180 years old", nor "it is 218 years old" etc


If you want to do it without regex, you could split the criminal strings on space:

var searchTerms = "18,old".Split(',')

criminals.Where(c => { 
  var words = c.Split(); 
  return searchTerms.All(st => words.Contains(st)); 
} );

but it's not so sophisticated; it would have old, in the words, so my search term above of old wouldn't find a match.. If you wanted to counter that, you'd have to split on more stuff (punctuation etc) than just space..


Now, about that case sensitivity...

  • Related