0

I have a text file named hello.txt with the following text:

[Hello] this is stack overflow and I Love [THIS] a lot. I use [Stack] for help.

I want just [ ] (brackets string) in a listbox.

I tried:

using (StringReader reader = new StringReader(File Location))
{
    string line;

    while ((line = reader.ReadLine()) != null)
    {
        string input = line;
        string output = input.Split('[', ']')[1];
        MessageBox.Show(output);
    }
}

But this doesn't work for me.

Racil Hilan
  • 24,690
  • 13
  • 50
  • 55
Pavel
  • 9
  • 2
  • Have a look at [Regular expressions](https://en.wikipedia.org/wiki/Regular_expression) – rickvdbosch Jun 19 '18 at 06:28
  • You can also explore mustache nuget package which provides you lost of predefined function to achieve something similar functionality http://mustache.github.io/ – Niraj Trivedi Jun 19 '18 at 09:33

4 Answers4

3

This is what you are looking for

string a = "Someone is [here]";
string b = Regex.Match(a, @"\[.*?\]").Groups[0].Value;
Console.WriteLine(b);

//or if you need all occurences
foreach(Match match in Regex.Matches(a, @"\[.*?\]"))
{
    Console.WriteLine(match.Groups[0].Value);
}
  • This will work, but the pattern in my answer is much faster. Almost double the speed. For a small text file, the difference is probably not big, but for a big text file, you'll notice the difference. – Racil Hilan Jun 19 '18 at 06:51
  • @RacilHilan care to explain why so? –  Jun 19 '18 at 06:54
  • What's there to explain? The pattern is faster because it is doing less work (i.e. less steps to find the matches). Try them in https://regex101.com/ and see. For the string in the question, your pattern needs 26 steps while mine needs 12. That's less than half of the steps for one line with 3 matches. – Racil Hilan Jun 19 '18 at 07:01
  • Also you need `Groups[0]`, not `Groups[1]`. You removed the parentheses from the accepted answer of the duplicate question and forgot to change the group. You can also use `match.Value` (no need for groups) or even just `match` like I did in my answer. – Racil Hilan Jun 19 '18 at 07:16
  • So @RacilHilan Sorry but i don't agree with you that your regex will be faster that's because i ran test with both pattern and timing says different story. –  Jun 19 '18 at 08:32
  • Disagreeing is fine, but saying that you "ran test" isn't helpful as nobody can see your test to verify. I didn't make an unsupported claim, running both patterns in regex101.com shows a crystal clear difference. Never mind the tests and think about them logically. Your pattern is comparing to the characters of the dot `.` pattern. That's a long list of possible characters to compare to. It is kind of similar to the `IN(...)` operator in SQL, comparing the value to a list of values. My pattern is simply comparing to one character. It's like `!= "]"`. Now that's obviously faster, isn't it? – Racil Hilan Jun 21 '18 at 21:29
1

You can use a regular expression like:

var pattern = @"\[[^\]]*]";
while ((line = reader.ReadLine()) != null) {
    var matches = Regex.Matches(line, pattern);

    foreach (var m in matches) {
        MessageBox.Show(m);
    }
}

This pattern looks for anything between square brackets that is not a closing square bracket.

If you want the string between the brackets without the brackets themselves, you can trim the brackets from each match:

MessageBox.Show(m.Value.Substring(1, m.Value.Length - 2));

Or you can use this pattern:

var pattern = @"\[([^\]]*)]";
while ((line = reader.ReadLine()) != null) {
    var matches = Regex.Matches(line, pattern);

    foreach (Match m in matches) {
        MessageBox.Show(m.Groups[1]);
    }
}
Racil Hilan
  • 24,690
  • 13
  • 50
  • 55
  • 1
    Why do you always create new variable `patern` inside `while` loop with same pattern? You can create it before while loop. – Roman Jun 19 '18 at 06:44
  • @RomanDoskoch I originally only provided the code inside `while`, but then decided to add `while` for clarity. I moved the pattern outside. Thanks for the note. – Racil Hilan Jun 19 '18 at 06:46
1

You can create a function for this which accept three parameter first input string, starting string and ending string and return list of value between those two string

private static IEnumerable<string> GetListOfString(string input, string start, string end)
{
   var regex = new Regex(Regex.Escape(start) + "(.*?)" + Regex.Escape(end));
   var matches = regex.Matches(input);
   return (from object match in matches select match.ToString()).ToList();
}
Niraj Trivedi
  • 2,370
  • 22
  • 24
0

Here is another way to do that using LINQ

string[] text = "[Hello] this is stack overflow and I Love [THIS] a lot. I use [Stack] for help.".Split(' ');
var wantedString = text.Where(s => s.StartsWith("[") && s.EndsWith("]"));
   foreach(string word in wantedString)
      {
           Console.WriteLine(word);
      }
Kaj
  • 806
  • 6
  • 16
  • 1
    It will fail for i.e. `... a [lot]. I ...` while splitting by spaces. – Roman Jun 19 '18 at 06:47
  • 1
    The `line` variable is string, not a string array. Converting it to a string array just to use LINQ makes no sense. – Racil Hilan Jun 19 '18 at 06:49
  • @RomanDoskoch yes that's true actually. Thank you. – Kaj Jun 19 '18 at 06:51
  • this is actually the first thing came to mind. I don't think there is a problem converting the string to array, except what @Roman Doskoch mentioned. – Kaj Jun 19 '18 at 06:53