C.J.
C.J.

Reputation: 3527

Split string base on the last N numbers of delimiters

I need help to develop a logic to split a string, but only based on the last 2 delimiters of the string.

Example inputs:

string s1 = "Dog \ Cat \ Bird \ Cow";

string s2 = "Hello \ World \ How \ Are \ You";

string s3 = "I \ am \ Peter";

Expected Outputs:

string[] newS1 = "Dog Cat", "Bird", "Cow"
string[] newS2 = "Hello World How", "Are", "You"
string[] newS3 = "I", "am", "Peter"

So, as you can see, I only want to split the string on the last 2 "\", and everything else before the last 2 "\" will be concatenated into one string.

I tried the .Split method but it will just split every "\" in a string.

Edited: If the string has less than 2 "\", it will just split according to whatever it has

Updates: Wow, these are a bunch of interesting solutions! Thank you a lot!

Upvotes: 3

Views: 193

Answers (6)

p.s.w.g
p.s.w.g

Reputation: 149040

Offering a regex solution:

var output = Regex.Split(input, @"\s*\\\s*([^\\]*?)\s*\\\s*(?=[^\\]*$)");

This split finds the second to last element and splits around that, but captures it in a group so it will be included in the output array.

For input "Dog \ Cat \ Bird \ Cow", this will produce { "Dog \ Cat", "Bird", "Cow" }. If you also need to strip the \ out of the first element that can be done with a simple replace:

output[0] = output[0].Replace(" \\", "");

Update: This version will correctly handle strings with only one delimiter:

var output = Regex.Split(str, @"\s*\\\s*([^\\]*?)\s*\\\s*(?=[^\\]*$)|(?<=^[^\\\s]*)\s*\\\s*(?=[^\\\s]*$)");

Update: And to match other delimiters like whitespace, "~", and "%", you can use a character class:

var output = Regex.Split(str, @"(?:[%~\s\\]+([^%~\s\\]+?)[%~\s\\]+|(?<=^[^%~\s\\]+)[%~\s\\]+)(?=[^%~\s\\]+$)");

The structure of this regex is slightly simpler than the previous one since it represents any sequence of one or more characters in the class [%~\s\\] as a delimiter, and any sequence of one or more characters in the negated character class [^%~\s\\] to be a segment. Note that the \s means 'whitespace' character.

You might also be able to simplify this further using:

var output = Regex.Split(str, @"(?:\W+(\w+)\W+|(?<=^\w+)\W+)(?=\w+$)");

Where \w matches any 'word' character (letters, digits, or underscores) and \W matches any 'non-word' character.

Upvotes: 5

John Gibb
John Gibb

Reputation: 10773

Try this:

var parts = s1.Split(new[] { " \\ " }, StringSplitOptions.None);
var partsCount = parts.Count();
var result = new[] { string.Join(" ", parts.Take(partsCount - 2)) }.Concat(parts.Skip(partsCount - 2));

Upvotes: 5

RyPope
RyPope

Reputation: 2725

Interesting question. My initial solution to this would be:

String[] tokens = theString.Split("\\");
String[] components = new String[3];
for(int i = 0; i < tokens.length - 2; i++)
{
    components[0] += tokens[i];
}

components[1] = tokens[tokens.length - 2];
components[2] = tokens[tokens.length - 1];

Upvotes: 1

Daniel A.A. Pelsmaeker
Daniel A.A. Pelsmaeker

Reputation: 50336

Looks like you want to Split the string on every <space>\<space>:

string input = @"Dog \ Cat \ Bird \ Cow";
string[] parts = input.Split(new string[]{@" \ "}, 
    StringSplitOptions.None);

And then Join everything with a space in between, except the final two parts:

// NOTE: Check that there are at least 2 parts.
string part0 = String.Join(" ", parts.Take(parts.Length - 2));
string part1 = parts[parts.Length - 2];
string part2 = parts[parts.Length - 1];

This will give you three strings, which you can put in an array.

string[] newParts = new []{ part0, part1, part2 };

In this example:

new [] { "Dog Cat", "Bird", "Cow" }

Upvotes: 2

korhner
korhner

Reputation: 733

Loop from the end of the string and count delimiters until you encounter two. Record index positions in 2 variables previously set to -1.

After the loop, if first var is -1, nothing happens, return whole string.

If second var is -1, create array of 2 strings, split using substring and return.

Create array of 3 string, split using information from two vars, return.

Hope you understood my pseudocode, give me a comment if you need help.

Upvotes: -1

LB2
LB2

Reputation: 4860

How about simply taking the output of split, then taking first N-2 items and Join back together, then create new string array of 3 items, first being output of Join, second being item N-1 of first split, and third being N of first split. I think that'll accomplish what you're trying to do.

Upvotes: 1

Related Questions