How to stop String.Concat(); from removing whitespaces? [duplicate] - c#

I would like to split a string with delimiters but keep the delimiters in the result.
How would I do this in C#?

If the split chars were ,, ., and ;, I'd try:
using System.Text.RegularExpressions;
...
string[] parts = Regex.Split(originalString, #"(?<=[.,;])")
(?<=PATTERN) is positive look-behind for PATTERN. It should match at any place where the preceding text fits PATTERN so there should be a match (and a split) after each occurrence of any of the characters.

If you want the delimiter to be its "own split", you can use Regex.Split e.g.:
string input = "plum-pear";
string pattern = "(-)";
string[] substrings = Regex.Split(input, pattern); // Split on hyphens
foreach (string match in substrings)
{
Console.WriteLine("'{0}'", match);
}
// The method writes the following to the console:
// 'plum'
// '-'
// 'pear'
So if you are looking for splitting a mathematical formula, you can use the following Regex
#"([*()\^\/]|(?<!E)[\+\-])"
This will ensure you can also use constants like 1E-02 and avoid having them split into 1E, - and 02
So:
Regex.Split("10E-02*x+sin(x)^2", #"([*()\^\/]|(?<!E)[\+\-])")
Yields:
10E-02
*
x
+
sin
(
x
)
^
2

Building off from BFree's answer, I had the same goal, but I wanted to split on an array of characters similar to the original Split method, and I also have multiple splits per string:
public static IEnumerable<string> SplitAndKeep(this string s, char[] delims)
{
int start = 0, index;
while ((index = s.IndexOfAny(delims, start)) != -1)
{
if(index-start > 0)
yield return s.Substring(start, index - start);
yield return s.Substring(index, 1);
start = index + 1;
}
if (start < s.Length)
{
yield return s.Substring(start);
}
}

Just in case anyone wants this answer aswell...
Instead of string[] parts = Regex.Split(originalString, #"(?<=[.,;])") you could use string[] parts = Regex.Split(originalString, #"(?=yourmatch)") where yourmatch is whatever your separator is.
Supposing the original string was
777- cat
777 - dog
777 - mouse
777 - rat
777 - wolf
Regex.Split(originalString, #"(?=777)") would return
777 - cat
777 - dog
and so on

This version does not use LINQ or Regex and so it's probably relatively efficient. I think it might be easier to use than the Regex because you don't have to worry about escaping special delimiters. It returns an IList<string> which is more efficient than always converting to an array. It's an extension method, which is convenient. You can pass in the delimiters as either an array or as multiple parameters.
/// <summary>
/// Splits the given string into a list of substrings, while outputting the splitting
/// delimiters (each in its own string) as well. It's just like String.Split() except
/// the delimiters are preserved. No empty strings are output.</summary>
/// <param name="s">String to parse. Can be null or empty.</param>
/// <param name="delimiters">The delimiting characters. Can be an empty array.</param>
/// <returns></returns>
public static IList<string> SplitAndKeepDelimiters(this string s, params char[] delimiters)
{
var parts = new List<string>();
if (!string.IsNullOrEmpty(s))
{
int iFirst = 0;
do
{
int iLast = s.IndexOfAny(delimiters, iFirst);
if (iLast >= 0)
{
if (iLast > iFirst)
parts.Add(s.Substring(iFirst, iLast - iFirst)); //part before the delimiter
parts.Add(new string(s[iLast], 1));//the delimiter
iFirst = iLast + 1;
continue;
}
//No delimiters were found, but at least one character remains. Add the rest and stop.
parts.Add(s.Substring(iFirst, s.Length - iFirst));
break;
} while (iFirst < s.Length);
}
return parts;
}
Some unit tests:
text = "[a link|http://www.google.com]";
result = text.SplitAndKeepDelimiters('[', '|', ']');
Assert.IsTrue(result.Count == 5);
Assert.AreEqual(result[0], "[");
Assert.AreEqual(result[1], "a link");
Assert.AreEqual(result[2], "|");
Assert.AreEqual(result[3], "http://www.google.com");
Assert.AreEqual(result[4], "]");

A lot of answers to this! One I knocked up to split by various strings (the original answer caters for just characters i.e. length of 1). This hasn't been fully tested.
public static IEnumerable<string> SplitAndKeep(string s, params string[] delims)
{
var rows = new List<string>() { s };
foreach (string delim in delims)//delimiter counter
{
for (int i = 0; i < rows.Count; i++)//row counter
{
int index = rows[i].IndexOf(delim);
if (index > -1
&& rows[i].Length > index + 1)
{
string leftPart = rows[i].Substring(0, index + delim.Length);
string rightPart = rows[i].Substring(index + delim.Length);
rows[i] = leftPart;
rows.Insert(i + 1, rightPart);
}
}
}
return rows;
}

This seems to work, but its not been tested much.
public static string[] SplitAndKeepSeparators(string value, char[] separators, StringSplitOptions splitOptions)
{
List<string> splitValues = new List<string>();
int itemStart = 0;
for (int pos = 0; pos < value.Length; pos++)
{
for (int sepIndex = 0; sepIndex < separators.Length; sepIndex++)
{
if (separators[sepIndex] == value[pos])
{
// add the section of string before the separator
// (unless its empty and we are discarding empty sections)
if (itemStart != pos || splitOptions == StringSplitOptions.None)
{
splitValues.Add(value.Substring(itemStart, pos - itemStart));
}
itemStart = pos + 1;
// add the separator
splitValues.Add(separators[sepIndex].ToString());
break;
}
}
}
// add anything after the final separator
// (unless its empty and we are discarding empty sections)
if (itemStart != value.Length || splitOptions == StringSplitOptions.None)
{
splitValues.Add(value.Substring(itemStart, value.Length - itemStart));
}
return splitValues.ToArray();
}

Recently I wrote an extension method do to this:
public static class StringExtensions
{
public static IEnumerable<string> SplitAndKeep(this string s, string seperator)
{
string[] obj = s.Split(new string[] { seperator }, StringSplitOptions.None);
for (int i = 0; i < obj.Length; i++)
{
string result = i == obj.Length - 1 ? obj[i] : obj[i] + seperator;
yield return result;
}
}
}

I'd say the easiest way to accomplish this (except for the argument Hans Kesting brought up) is to split the string the regular way, then iterate over the array and add the delimiter to every element but the last.

To avoid adding character to new line try this :
string[] substrings = Regex.Split(input,#"(?<=[-])");

result = originalString.Split(separator);
for(int i = 0; i < result.Length - 1; i++)
result[i] += separator;
(EDIT - this is a bad answer - I misread his question and didn't see that he was splitting by multiple characters.)
(EDIT - a correct LINQ version is awkward, since the separator shouldn't get concatenated onto the final string in the split array.)

Iterate through the string character by character (which is what regex does anyway.
When you find a splitter, then spin off a substring.
pseudo code
int hold, counter;
List<String> afterSplit;
string toSplit
for(hold = 0, counter = 0; counter < toSplit.Length; counter++)
{
if(toSplit[counter] = /*split charaters*/)
{
afterSplit.Add(toSplit.Substring(hold, counter));
hold = counter;
}
}
That's sort of C# but not really. Obviously, choose the appropriate function names.
Also, I think there might be an off-by-1 error in there.
But that will do what you're asking.

veggerby's answer modified to
have no string items in the list
have fixed string as delimiter like "ab" instead of single character
var delimiter = "ab";
var text = "ab33ab9ab"
var parts = Regex.Split(text, $#"({Regex.Escape(delimiter)})")
.Where(p => p != string.Empty)
.ToList();
// parts = "ab", "33", "ab", "9", "ab"
The Regex.Escape() is there just in case your delimiter contains characters which regex interprets as special pattern commands (like *, () and thus have to be escaped.

using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace ConsoleApplication9
{
class Program
{
static void Main(string[] args)
{
string input = #"This;is:a.test";
char sep0 = ';', sep1 = ':', sep2 = '.';
string pattern = string.Format("[{0}{1}{2}]|[^{0}{1}{2}]+", sep0, sep1, sep2);
Regex regex = new Regex(pattern);
MatchCollection matches = regex.Matches(input);
List<string> parts=new List<string>();
foreach (Match match in matches)
{
parts.Add(match.ToString());
}
}
}
}

I wanted to do a multiline string like this but needed to keep the line breaks so I did this
string x =
#"line 1 {0}
line 2 {1}
";
foreach(var line in string.Format(x, "one", "two")
.Split("\n")
.Select(x => x.Contains('\r') ? x + '\n' : x)
.AsEnumerable()
) {
Console.Write(line);
}
yields
line 1 one
line 2 two

I came across same problem but with multiple delimiters. Here's my solution:
public static string[] SplitLeft(this string #this, char[] delimiters, int count)
{
var splits = new List<string>();
int next = -1;
while (splits.Count + 1 < count && (next = #this.IndexOfAny(delimiters, next + 1)) >= 0)
{
splits.Add(#this.Substring(0, next));
#this = new string(#this.Skip(next).ToArray());
}
splits.Add(#this);
return splits.ToArray();
}
Sample with separating CamelCase variable names:
var variableSplit = variableName.SplitLeft(
Enumerable.Range('A', 26).Select(i => (char)i).ToArray());

I wrote this code to split and keep delimiters:
private static string[] SplitKeepDelimiters(string toSplit, char[] delimiters, StringSplitOptions splitOptions = StringSplitOptions.None)
{
var tokens = new List<string>();
int idx = 0;
for (int i = 0; i < toSplit.Length; ++i)
{
if (delimiters.Contains(toSplit[i]))
{
tokens.Add(toSplit.Substring(idx, i - idx)); // token found
tokens.Add(toSplit[i].ToString()); // delimiter
idx = i + 1; // start idx for the next token
}
}
// last token
tokens.Add(toSplit.Substring(idx));
if (splitOptions == StringSplitOptions.RemoveEmptyEntries)
{
tokens = tokens.Where(token => token.Length > 0).ToList();
}
return tokens.ToArray();
}
Usage example:
string toSplit = "AAA,BBB,CCC;DD;,EE,";
char[] delimiters = new char[] {',', ';'};
string[] tokens = SplitKeepDelimiters(toSplit, delimiters, StringSplitOptions.RemoveEmptyEntries);
foreach (var token in tokens)
{
Console.WriteLine(token);
}

Related

Remove all but specified substring from string

I have a string that contains several instances of a substring, as well as other text. The substring is specified by beginning with a given sequence of letters (e.g. CNTY) and ending with a double slash (//). How could I efficiently remove all text that does not fall inside the specified substring? Thanks for the help. I found that this Regex will return the result needed:
string result = Regex.Matches(text, "CNTY(.*)//").Cast<Match>().Aggregate("", (s, t) => s + t.Value, s => s);
But, I have another more complicated substring, which begins with WEATHLOC, then contains wildcard text across several lines, and ends with a line beginning RMKS, more wildcard text, and then //. Here is an example:
WEATHLOC/ICAO:KCOS//
OBSTIME/052005Z//
WIND/360/10//
VSBY/10/SM//
CLDLYR/-/LYR:BKN//
TEMP/MAXTEMP:15/MINTEMP:18//
ALTSTG/HG:29.92//
RMKS/SAMPLE//
Everything from WEATHLOC to the final // needs to be captured, and I can only rely on its beginning with WEATHLOC and ending with RMKS*//. Is there a way to express that in a Regex match?
This should work:
string text = "hiCNTYhello//content What /-CNTYworld//12texCNTY!//That's it";
string search = "CNTY(.*?)//";
MatchCollection matches = Regex.Matches(text, search);
Will match "hello", "world" and "!"
This little code segment works. The RegEx method was too difficult for me, but this does work. We are trying to check if we are in bounds of CNTY // and to output that text to the StringBuilder.
static void Main(string[] args)
{
var input = #"CNTYTestingTesting//This is some more test CNTY1234//And some moreCNTYWhat is this?//";
var sb = new StringBuilder();
int inCnty = -1;
for (int i = 0; i < input.Length; i ++)
{
// Test for start
if (i < input.Length - 4)
{
if (input.Substring(i, 4) == "CNTY")
{
inCnty = i + 4; // Index of first CNTY
}
}
// Test for end
if (i < input.Length - 1)
{
if (input.Substring(i, 2) == #"//")
{
inCnty = -1; // Reset
}
}
// Test if we are in the segment
if (i >= inCnty && inCnty > 0)
{
// Outside string
sb.Append(input[i]);
}
}
var output = sb.ToString();
Console.WriteLine(output);
Console.Read();
}

How to reverse an array of strings without changing the position of special characters in C#

I'm working on reversing a sentence. I'm able to do it. But I'm not sure, how to reverse the word without changing the special characters positions. I'm using regex but as soon as it finds the special characters it's stopping the reversal of the word.
Following is the code:
Console.WriteLine("Enter:");
string w = Console.ReadLine();
string rw = String.Empty;
String[] arr = w.Split(' ');
var regexItem = new Regex("^[a-zA-Z0-9]*$");
StringBuilder appendString = new StringBuilder();
for (int i = 0; i < arr.Length; i++)
{
char[] chararray = arr[i].ToCharArray();
for (int j = chararray.Length - 1; j >= 0; j--)
{
if (regexItem.IsMatch(rw))
{
rw = appendString.Append(chararray[j]).ToString();
}
}
sb.Append(' ');
}
Console.WriteLine(rw);
Console.ReadLine();
Example : Input
Marshall! Hello.
Expected output
llahsram! olleh.
A basic solution with regex and LINQ. Try it online.
public static void Main()
{
Console.WriteLine("Marshall! Hello.");
Console.WriteLine(Reverse("Marshall! Hello."));
}
public static string Reverse(string source)
{
// we split by groups to keep delimiters
var parts = Regex.Split(source, #"([^a-zA-Z0-9])");
// if we got a group of valid characters
var results = parts.Select(x => x.All(char.IsLetterOrDigit)
// we reverse it
? new string(x.Reverse().ToArray())
// or we keep the delimiters as it
: x);
// then we concat all of them
return string.Concat(results);
}
The same solution without LINQ. Try it online.
public static void Main()
{
Console.WriteLine("Marshall! Hello.");
Console.WriteLine(Reverse("Marshall! Hello."));
}
public static bool IsLettersOrDigits(string s)
{
foreach (var c in s)
{
if (!char.IsLetterOrDigit(c))
{
return false;
}
}
return true;
}
public static string Reverse(char[] s)
{
Array.Reverse(s);
return new string(s);
}
public static string Reverse(string source)
{
var parts = Regex.Split(source, #"([^a-zA-Z0-9])");
var results = new List<string>();
foreach(var x in parts)
{
results.Add(IsLettersOrDigits(x)
? Reverse(x.ToCharArray())
: x);
}
return string.Concat(results);
}
This is a solution without LINQ. I wasn't sure about what are considered special characters.
string sentence = "Marshall! Hello.";
List<string> words = sentence.Split(' ').ToList();
List<string> reversedWords = new List<string>();
foreach (string word in words)
{
char[] arr = new char[word.Length];
for( int i=0; i<word.Length; i++)
{
if(!Char.IsLetterOrDigit((word[i])))
{
for ( int x=0; x< i; x++)
{
arr[x] = arr[x + 1];
}
arr[i] = word[i];
}
else
{
arr[word.Length - 1 - i] = word[i];
}
}
reversedWords.Add(new string(arr));
}
string reversedSentence = string.Join(" ", reversedWords);
Console.WriteLine(reversedSentence);
And this is the output:
Updated Output = llahsraM! olleH.
Here is a non-regex version that does what you want:
var sentence = "Hello, john!";
var parts = sentence.Split(' ');
var reversed = new StringBuilder();
var charPositions = sentence.Select((c, idx) => new { Char = c, Index = idx })
.Where(_ => !char.IsLetterOrDigit(_.Char));
for (int i = 0; i < parts.Length; i++)
{
var chars = parts[i].ToCharArray();
for (int j = chars.Length - 1; j >= 0; j--)
{
if (char.IsLetterOrDigit(chars[j]))
{
reversed.Append(chars[j]);
}
}
}
foreach (var ch in charPositions)
{
reversed.Insert(ch.Index, ch.Char);
}
// olleH, nhoj!
Console.WriteLine(reversed.ToString());
Basically the trick is to remember the position of special (i.e. non letter or digit) characters and insert them at the end to those positions.
This solution is without LINQ and Regex. It may not be an efficient answer but working properly for small string values.
// This will reverse the string and special characters will just stay there.
public string ReverseString(string rString)
{
StringBuilder ss = new StringBuilder(rString);
int y = 0;
// The idea is to swap values. Like swapping first value with last one. It will keep swapping unless it reaches at the middle of the string where no swapping will be needed.
// This first loop is to detect first values.
for(int i=rString.Length-1;i>=0;i--)
{
// This condition is to check if the values is String or not. If it is not string then it is considered as special character which will just stay there at same old position.
if(Char.IsLetter(Convert.ToChar(rString.Substring(i,1))))
{
// This is second loop which is starting from end to swap values from end with first.
for (int k = y; k < rString.Length; k++)
{
// Again checking last values if values are string or not.
if (Char.IsLetter(Convert.ToChar(rString.Substring(k, 1))))
{
// This is swapping. So st1 is First value in that string
// st2 is the last item in that string
char st1 = Convert.ToChar(rString.Substring(k, 1));
char st2 = Convert.ToChar(rString.Substring(i, 1));
//This is swapping. So last item will go to first position and first item will go to last position, To make sure string is reversed.
// Remember when the string value is Special Character, swapping will move forward without swapping.
ss[rString.IndexOf(rString.Substring(i, 1))] = st1;
ss[rString.IndexOf(rString.Substring(k, 1))] = st2;
y++;
// When the swapping is done for first 2 items. The loop will stop to change the values.
break;
}
else
{
// This is just increment if value was Special character.
y++;
}
}
}
}
return ss.ToString();
}
Thanks!

How to split a string with delimited as pipe (which is not inside double quotes

I have a string like below, which is pipe separated. it has double quotes around string (ex: "ANI").
How do I split this with pipe delimiter (which are not inside double quotes) ?
511186|"ANI"|"ABCD-102091474|E|EFG"||"2013-07-20 13:47:19.556"
And splitted values shoule be like below:
511186
"ANI"
"ABCD-102091474|E|EFG"
"2013-07-20 13:47:19.556"
Any help would be appreciated!
EDIT
The answer that I accepted, did not work for those strings which has double quotes inside. Any idea, what should be the issue ?
using System.Text.RegularExpressions;
string regexFormat = string.Format(#"(?:^|\{0})(""[^""]*""|[^\{0}]*)", '|');
string[] result = Regex.Matches("111001103|\"E\"|\"BBB\"|\"XXX\"|||10000009|153086649|\"BCTV\"|\"REV\"|||1.00000000|||||\"ABC-BT AD\"|\"\"\"ABC - BT\"\" AD\"|||\"N\"||\"N\"|||\"N\"||\"N",regexFormat)
.Cast<Match>().Select(m => m.Groups[1].Value).ToArray();
foreach(var i in result)
Console.WriteLine(i)
You can use a regular expression to match the items in the string:
string[] result = Regex.Matches(s, #"(?:^|\|)(""[^""]*""|[^|]*)")
.Cast<Match>()
.Select(m => m.Groups[1].Value)
.ToArray();
Explanation:
(?: A non-capturing group
^|\| Matches start of string or a pipe character
) End of group
( Capturing group
"[^"]*" Zero or more non-quotes surrounded by quotes
| Or
[^|]* Zero or more non-pipes
) End of group
Here is one way to do it:
public List<string> Parse(string str)
{
var parts = str.Split(new[] {"|"}, StringSplitOptions.None);
List<string> result = new List<string>();
for (int i = 0; i < parts.Length; i++)
{
string part = parts[i];
if (IsPartStart(part))
{
List<string> sub_parts = new List<string>();
do
{
sub_parts.Add(part);
i++;
part = parts[i];
} while (!IsPartEnd(part));
sub_parts.Add(part);
part = string.Join("|", sub_parts);
}
result.Add(part);
}
return result;
}
private bool IsPartStart(string part)
{
return (part.StartsWith("\"") && !part.EndsWith("\"")) ;
}
private bool IsPartEnd(string part)
{
return (!part.StartsWith("\"") && part.EndsWith("\""));
}
This works by splitting everything, and it then joins some of the parts that needs joining by searching for parts that starts with " and corresponding parts that ends with ".
string.Split("|", inputString);
...will give you the individual parts, but will fail if any of the parts have a pipe separator in them.
If it's a CSV file, following all the usual CSV rules about character-escaping, etc. (but using a pipe symbol instead of comma), then you should look at using CsvHelper, a NuGet package designed for reading and writing CSV files. It does all the hard work, and deals with all the corner cases that you'd otherwise have to do yourself.
Here's how I'd do it. It's fairly simple and I think you'll find it's very fast as well. I haven't run any tests, but I'm pretty confident that it's faster than regular expressions.
IEnumerable<string> Parse(string s)
{
int pos = 0;
while (pos < s.Length)
{
char endChar = '|';
// Test for quoted value
if (s[pos] == '"')
{
pos++;
endChar = '"';
}
// Extract this value
int newPos = s.IndexOf(endChar, pos);
if (newPos < 0)
newPos = s.Length;
yield return s.Substring(pos, newPos - pos);
// Move to start of next value
pos = newPos + 1;
if (pos < s.Length && s[pos] == '|')
pos++;
}
}

Find and count latter pair from a string by alphabetical order

I am working on a small project which is in C# where I want to find and count the latter pairs which comes in alphabetical order by ignoring spaces and special characters.
e.g.
This is a absolutely easy.
Here my output should be
hi 1
ab 1
I refereed This post but not getting exact idea for pair latter count.
First I remove the spaces and special characters as you specified by simply going though the string and checking whether the current character is a letter:
private static string GetLetters(string s)
{
string newString = "";
foreach (var item in s)
{
if (char.IsLetter(item))
{
newString += item;
}
}
return newString;
}
Than I wrote a method which checks if the next letter is in alphabetical order using simple logic. I lower the character's case and check if the current character's ASCII code + 1 is equal to the next one's. If it is, of course they are the same:
private static string[] GetLetterPairsInAlphabeticalOrder(string s)
{
List<string> pairs = new List<string>();
for (int i = 0; i < s.Length - 1; i++)
{
if (char.ToLower(s[i]) + 1 == char.ToLower(s[i + 1]))
{
pairs.Add(s[i].ToString() + s[i+1].ToString());
}
}
return pairs.ToArray();
}
Here is how the main method will look like:
static void Main()
{
string s = "This is a absolutely easy.";
s = GetLetters(s);
string[] pairOfLetters = GetLetterPairsInAlphabeticalOrder(s);
foreach (var item in arr)
{
Console.WriteLine(item);
}
}
First, I would normalize the string to reduce confusion from special characters like this:
string str = "This is a absolutely easy.";
Regex rgx = new Regex("[^a-zA-Z]");
str = rgx.Replace(str, "");
str = str.ToLower();
Then, I would loop over all of the characters in the string and see if their neighbor is the next letter in the alphabet.
Dictionary<string, int> counts = new Dictionary<string, int>();
for (int i = 0; i < str.Length - 1; i++)
{
if (str[i+1] == (char)(str[i]+1))
{
string index = "" + str[i] + str[i+1];
if (!counts.ContainsKey(index))
counts.Add(index, 0);
counts[index]++;
}
}
Printing the counts from there is pretty straightforward.
foreach (string s in counts.Keys)
{
Console.WriteLine(s + " " + counts[s]);
}

How to split a string on the nth occurrence?

What I want to do is to split on the nth occurrence of a string (in this case it's "\t"). This is the code I'm currently using and it splits on every occurrence of "\t".
string[] items = input.Split(new char[] {'\t'}, StringSplitOptions.RemoveEmptyEntries);
If input = "one\ttwo\tthree\tfour", my code returns the array of:
one
two
three
four
But let's say I want to split it on every "\t" after the second "\t". So, it should return:
one two
three
four
There is nothing built in.
You can use the existing Split, use Take and Skip with string.Join to rebuild the parts that you originally had.
string[] items = input.Split(new char[] {'\t'},
StringSplitOptions.RemoveEmptyEntries);
string firstPart = string.Join("\t", items.Take(nthOccurrence));
string secondPart = string.Join("\t", items.Skip(nthOccurrence))
string[] everythingSplitAfterNthOccurence = items.Skip(nthOccurrence).ToArray();
An alternative is to iterate over all the characters in the string, find the index of the nth occurrence and substring before and after it (or find the next index after the nth, substring on that etc... etc... etc...).
[EDIT] After re-reading the edited OP, I realise this doesn't do what is now asked. This will split on every nth target; the OP wants to split on every target AFTER the nth one.
I'll leave this here for posterity anyway.
If you were using the MoreLinq extensions you could take advantage of its Batch method.
Your code would then look like this:
string text = "1\t2\t3\t4\t5\t6\t7\t8\t9\t10\t11\t12\t13\t14\t15\t16\t17";
var splits = text.Split('\t').Batch(5);
foreach (var split in splits)
Console.WriteLine(string.Join("", split));
I'd probably just use Oded's implementation, but I thought I'd post this for an alternative approach.
The implementation of Batch() looks like this:
public static class EnumerableExt
{
public static IEnumerable<IEnumerable<TSource>> Batch<TSource>(this IEnumerable<TSource> source, int size)
{
TSource[] bucket = null;
var count = 0;
foreach (var item in source)
{
if (bucket == null)
bucket = new TSource[size];
bucket[count++] = item;
if (count != size)
continue;
yield return bucket;
bucket = null;
count = 0;
}
if (bucket != null && count > 0)
yield return bucket.Take(count);
}
}
It is likely that you will have to split and re-combine. Something like
int tabIndexToRemove = 3;
string str = "My\tstring\twith\tloads\tof\ttabs";
string[] strArr = str.Split('\t');
int numOfTabs = strArr.Length - 1;
if (tabIndexToRemove > numOfTabs)
throw new IndexOutOfRangeException();
str = String.Empty;
for (int i = 0; i < strArr.Length; i++)
str += i == tabIndexToRemove - 1 ?
strArr[i] : String.Format("{0}\t", strArr[i]);
Result:
My string withloads of tabs
I hope this helps.
// Return a substring of str upto but not including
// the nth occurence of substr
function getNth(str, substr, n) {
var idx;
var i = 0;
var newstr = '';
do {
idx = s.indexOf(c);
newstr += str.substring(0, idx);
str = str.substring(idx+1);
} while (++i < n && (newstr += substr))
return newstr;
}

Categories