Michael
Michael

Reputation: 251

How to split a string on the 3rd occurence of a char C#

I was wondering is there a way to split a string on the 3rd occurence of a char? When splitting previously i was using:

line.Substring(line.LastIndexOf(']') +1);

I hadn't realised some of my strings had extra square brackets than others so ideally i need to split on the 3rd occurence of ']' as this is the same position on every string.

Input: [Wed Dec 17 14:40:28 2014] [error] [client 143.117.101.166] File does not exist:

Output:

[Wed Dec 17 14:40:28 2014] [error] [client 143.117.101.166]

File does not exist:

Upvotes: 5

Views: 3478

Answers (9)

Arash
Arash

Reputation: 885

Use Regex to solve the problem,this will capture content with []

string input = " [Wed Dec 17 14:40:28 2014] [error] [client 143.117.101.166] File does not exist";
var regex = new Regex("\\[(.*?)\\]");
var matches = regex.Matches(input);
foreach (var match in matches) // e.g. you can loop through your matches like this
{
   //yourmatch
}

Upvotes: 2

Creo
Creo

Reputation: 123

I would do it like this:

public static class SplitExtension
{
    public static string[] Split(this string self, char separator, int occurrence)
    {
        return self.Split(new string(separator, 1), occurrence);
    }

    public static string[] Split(this string self, string separator, int occurrence)
    {
        string[] chunks = self.Split(new[] { separator }, StringSplitOptions.None);
        string firstPart = string.Join(separator, chunks.Take(occurrence)) + separator;
        string secondPart = string.Join(separator, chunks.Skip(occurrence));
        return new string[] { firstPart, secondPart };
    }
}

... and then use it like this:

string input = "[Wed Dec 17 14:40:28 2014] [error] [client 143.117.101.166] File does not exist";
string[] output = input.Split(']', 3);

// output[0] = "[Wed Dec 17 14:40:28 2014] [error] [client 143.117.101.166]";
// output[1] = " File does not exist";

Upvotes: 0

jlmt
jlmt

Reputation: 1996

Another possibility using Linq:

(Take chars from the string until you've seen three square close brackets, then send the output back to the String constructor as an array.)

static void Main(string[] args)
{
    string test = "[Wed Dec 17 14:40:28 2014] [error] [client 143.117.101.166] File does not exist:";

    var result = SplitOnChar(test, ']', 3);

    Debug.WriteLine(result.Item1);
    Debug.WriteLine(result.Item2);
}

static Tuple<string, string> SplitOnChar(string input, char c, int occurrence)
{
    int charCount = 0;
    string firstPart = new String(input.TakeWhile(x => (x == ']' ? charCount++ : charCount) < 3).ToArray());
    string lastPart = input.Substring(firstPart.Length);
    return Tuple.Create(firstPart, lastPart);
}

Credit goes to this answer for the technique: LINQ, simplifying expression - take while sum of taken does not exceed given value

Upvotes: 0

Bassel Eid
Bassel Eid

Reputation: 182

you need to split the string first then take the index of the 3rd ]

line.Substring(line.IndexOf(line.Split(']')[3]));

or more easy as you said the 3rd index of ] is the same, put it fixed

line.Substring(59);

Upvotes: 7

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726499

This input can be matched with a regular expression:

\[[^\]]*\]\s*\[[^\]]*\]\s*\[[^\]]*\]

This looks scary because of escape sequences, but the structure is very straightforward: it matches three occurrences of [ + zero or more non-] + ], separated by zero or more spaces.

var s = "[Wed Dec 17 14:40:28 2014] [error] [client 143.117.101.166] File does not exist:";
var r = new Regex(@"(\[[^\]]*\]\s*\[[^\]]*\]\s*\[[^\]]*\])(.*)$");
var m = r.Match(s);
if (m.Success) {
    Console.WriteLine("Prefix: {0}", m.Groups[1]);
    Console.WriteLine("Error: {0}", m.Groups[2]);
}

Demo.

Upvotes: 5

Rajesh Kumar
Rajesh Kumar

Reputation: 89

You can use LINQ:

string input = "[Wed Dec 17 14:40:28 2014] [error] [client 143.117.101.166] File does not exist:";

var result = input.Select((ch, ind) => new { ch, ind }).Where(x => x.ch == ']').Skip(2).FirstOrDefault();

string output = input.Substring(result.ind + 1);

Upvotes: 0

dcg
dcg

Reputation: 4219

If this is a common task you can create an extension method that gives you all the positions where the character you want is, something like:

static class ExtMethods
{
    public static IEnumerable<int> IndexesOf(this string str, char c)
    {
        for (int i = 0; i < str.Length; i++)
        {
            if (str[i] == c)
            yield return i;
        }
    }
}

Then you can get the position of the third ] with something like:

int thirdPos = str.IndexesOf(']').Take(3).Last();

Upvotes: 0

Shardul Wagh
Shardul Wagh

Reputation: 80

Okay, as far as I know, C# does not have an inbuilt function for what you seek. Using Regular Expressions is an alternative you could use.

If not, there's another way in which you could get your desired outcome, but that will work only for these particular set of strings. But again, REGEX too has the same problem.

In your string, if you observe the first two occurrences of ] are always followed by [

What I am suggesting is, whenever you find the index of ] you could just check the next character in the string, and if the next character is not [ only then you have to split.

There are infinite number of ways to solve your problem, select the one which makes your code the most modular.

Hope this helps.

Upvotes: 0

atlaste
atlaste

Reputation: 31106

I'd go for a simple Split in this case:

var items = line.Split(new[]{']','['},StringSplitOptions.RemoveEmptyEntries);
if (items.Count > 3) { 
   /* use items[2], or whatever you need... */ 
}

Because the first items are always bracketted and the same format, this will work.

Upvotes: 0

Related Questions