Shuffle the characters - c#

I need to shuffle the characters in the way that at each iteration, the odd characters of the string are combined and wrapped to its beginning, and the even characters are wrapped to the end.
public static string ShuffleChars(string source, int count)
{
if (string.IsNullOrEmpty(source))
{
throw new ArgumentException("source is null or empty");
}
if (string.IsNullOrWhiteSpace(source))
{
throw new ArgumentException("source is white space");
}
if (count < 0)
{
throw new ArgumentException("count < 0");
}
for (int j = 0; j < count; j++)
{
string tempOdd = string.Empty;
string tempEven = string.Empty;
for (int i = 0; i < source.Length; i++)
{
if (i % 2 == 0)
{
tempOdd += source[i];
}
else if (i % 2 != 0)
{
tempEven += source[i];
}
}
source = tempOdd + tempEven;
}
return source;
}
This works perfectly fine BUT, when count = int.MaxValue then it is in an seemingly endless loading
The task given to me says that I will have to optimize this, and people adviced using StringBuilder, so I came up with something like this:
public static string ShuffleChars(string source, int count)
{
if (string.IsNullOrEmpty(source))
{
throw new ArgumentException("source is null or empty");
}
if (string.IsNullOrWhiteSpace(source))
{
throw new ArgumentException("source is white space");
}
if (count < 0)
{
throw new ArgumentException("count < 0");
}
StringBuilder sourceString = new StringBuilder(source);
StringBuilder tempOdd = new StringBuilder(string.Empty);
StringBuilder tempEven = new StringBuilder(string.Empty);
for (int j = 0; j < count; j++)
{
tempOdd.Clear();
tempEven.Clear();
for (int i = 0; i < sourceString.Length; i++)
{
if (i % 2 == 0)
{
tempOdd.Append(sourceString[i]);
}
else
{
tempEven.Append(sourceString[i]);
}
}
sourceString = tempOdd.Append(tempEven);
}
return sourceString.ToString();
}
As far as I understand when I clear tempOdd and tempEven, sourceString gets cleared as well, and that is why when I shuffle the string more than once it returns me empty string.
May be there are other ways to optimize this?

The problem is that you are setting sourceString = tempOdd.Append(tempEven);. I.e., sourceString is now a reference pointing to the same StringBuilder object than tempOdd! Then you are clearing tempOdd, which is in fact is the same object as sourceString. And btw., you have inverted even and odd. i % 2 == 0 is even.
Instead, append both, the odd and even string to sourceString after having cleared it.
sourceString.Clear();
sourceString.Append(tempOdd).Append(tempEven);
Note that Append returns the StringBuilder itself. Therefore, this is equivalent to
sourceString.Clear();
sourceString.Append(tempOdd);
sourceString.Append(tempEven);
Strings are immutable. Therefore, when you are manipulating strings, you are always creating new strings. E.g., when you add a character to tempOdd, this creates a new string object having a length longer by one character. Then it copies the old string into the new one and appends the character. This generates a lot of new objects and involves a lot of copying.
StringBuilder works with an internal mutable buffer. Since the size of these buffers remains the same at each iteration, the characters can be appended to the already existing buffers, with no object creation (except for the initialization phase) and copying of strings involved.
Therefore StringBuilder is more efficient than string.
But there are more optimizations you can make, as #JL0PD already pointed out. The length of the even and odd parts is known in advance. Therefore, we can copy the characters to the final places and thus avoid having to concatenate the result at the end.
Also, this solution reuses the same character buffers at each iteration. To achieve this, we must swap the two buffers at each iteration to make the previous result the new source.
public static string ShuffleChars(string source, int count)
{
if (string.IsNullOrWhiteSpace(source)) {
throw new ArgumentException("source is null or empty or white space");
}
if (count < 0) {
throw new ArgumentException("count < 0");
}
// Initialize the wrong way, since we are swapping later.
var resultChars = source.ToCharArray();
var sourceChars = new char[source.Length];
for (int j = 0; j < count; j++) {
// Swap source and result. This enables us to reuse the same buffers.
var temp = sourceChars;
sourceChars = resultChars;
resultChars = temp;
// We don't need to clear, since we fill every character position anyway.
int iOdd = 0;
int iEven = source.Length / 2;
for (int i = 0; i < source.Length; i++) {
if (i % 2 == 0) {
resultChars[iEven++] = sourceChars[i];
} else {
resultChars[iOdd++] = sourceChars[i];
}
}
}
return new String(resultChars);
}

Related

For-loop looping too often because it's not exiting properly (performance)

I currently have an array with a size of one million, and a method that parses new objects (each one with a key and value) or overwrites an object in case a new object has an already existing key. The thing is that the loop for the overwriting part is taking an extremely long time with an array this big because it is not exiting properly. For every element it parses it checks every index, so for a thousand elements to parse it would do a billion checks, which is obviously not desired behaviour.
private const int ARRAY_SIZE = 1000000;
private Paar[] pArr = new Paar[ARRAY_SIZE];
public void Put(string key, object value)
{
bool wasReplaced = false;
for (int i = 0; i < pArr.Length; i++)
{
if (pArr[i] != null && pArr[i].key == key)
{
pArr[i] = new Paar(key, value);
wasReplaced = true;
}
}
if (wasReplaced == false)
{
for (int i = 0; i < pArr.Length; i++)
{
if (pArr[i] == null)
{
pArr[i] = new Paar(key, value);
break;
}
else if (i >= pArr.Length)
{
throw new Exception("All slots full");
}
}
}
}
Edit: Note that I am using two loops to prevent the overwriting function from being able to parse an object with a duplicate key and new value into an empty index if there happens to be one before the duplicate key's index (for example if I set one or more random indexes to null).
string keyparse = "Key";
string valueparse = "Value";
Random rnd = new Random();
int wdh = 1000;
for (int i = 0; i < wdh; i++)
{
myMap.Put(keyparse + rnd.Next(1, 10000), valueparse + rnd.Next(1, 10000));
}
I tried to make the first part of the function add 1 to an int and break if the int reaches the number of elements parsed, but it does not seem to function properly, and neither does it affect the time taken by the function.
bool wasReplaced = false;
int count = 0;
for (int i = 0; i < pArr.Length; i++)
{
if (pArr[i] != null)
{
count += 1;
if (pArr[i] != null && pArr[i].key == key)
{
pArr[i] = new Paar(key, value);
count += 1;
break;
}
else if (count == 1000)
{
break;
}
}
}
I don't really know why this wouldn't work or how else I could approach this, so I'm kind of stuck here... Any help is greatly appreciated!
Use a Dictionary - but you write it's for practice ...
In that case:
Speedup 1: (Assuming your key is unique!)
for (int i = 0; i < pArr.Length; i++)
{
if (pArr[i] != null && pArr[i].key == key)
{
pArr[i] = new Paar(key, value);
// wasReplaced = true;
return;
}
}
Speedup 2: When traversing in the first for-loop, save the first position of an empty space. Then you can use that instantly and only have to iterate the array once.
int empty = -1;
for (int i = 0; i < pArr.Length; i++)
{
if (pArr[i] != null )
{
if (pArr[i].key == key)
{
pArr[i] = new Paar(key, value);
return;
}
}
else if( empty < 0 )
{
empty = i;
}
}
if( pArr >= 0 )
pArr[empty] = new Paar(key,value);
else // Array has been fully traversed without match and without empty space
throw new Exception("All slots full");
Speedup 3: You could keep track of the highest index used, so you can break the for-loop early.
Mind that these measures are only to speed up that part. I did not take into account many other considerations and possible techniques like hashing, thread-safety, etc.
There are several things may done here-
A minor improvement will be break your loop when you set wasReplaced = true
if (pArr[i] != null && pArr[i].key == key)
{
pArr[i] = new Paar(key, value);
wasReplaced = true;
break;
}
But it is not a good solution
Another solution is you may use TPL (Task Parallel Library), to use multithread and multicore. There is a ParallelForEach() loop there.
Another solution is use Dictionary<string, string> to store your values, instead of using an array. Dictionary<> uses hash map, you will get a better performance.
If you still want to use your own implementation with array, then try to use hashing or heap algorithm to store your data. By using hashing or heap you can store/get/update data by O(log(n)) time complexity.
private List<Paar> pArr = new list<Paar>();
public void Put(string key, object value)
{
(from p in pArr
where p!= null && p.key!=key select p).ToList()
.ForEach(x => x.key== key, x.Value==value);
}
Try with Linq Query
As written in a comment, I suggest you to use Dictionary instead of Paar class, so you can do something like:
int ARRAY_SIZE= 100000;
Dictionary<string, object> pArr = new Dictionary<string, object>()
public void Put(string key, string object)
{
if(pArr.ContainsKey(key))
pArr[key] = value;
else
{
if(pArr.Count() >= ARRAY_SIZE)
throw new Exception("All slots full");
pArr.Add(key, value)
}
}
If you need to use Paar class, you can use the .ToDictionary(x => x.key, x => x.value) to work with it.
Given that you don't want to use a dictionary and there may be a match anywhere within the array, then the best you can do is search the whole array until you find a match, and capture the index of the first null item along the way (for an insertion point if a match is not found):
public static void Put(string key, object value)
{
int insertionIndex = -1;
for (int i = 0; i < pArr.Length; i++)
{
if (pArr[i] != null)
{
if (pArr[i].Key == key)
{
insertionIndex = i;
break;
}
}
else if (insertionIndex < 0)
{
insertionIndex = i;
}
}
if (insertionIndex < 0)
{
throw new Exception("All slots full");
}
else
{
pArr[insertionIndex] = new Paar(key, value);
}
}
I solved this by declaring an instance variable and a local variable which are then to be compared. I also fixed a logical error I made (now the second loop counts properly and the first loop doesn't count anymore if it overwrites something but instead returns).
The method still functions the same but now runs much more efficiently (took 7 seconds for 5kk parses compared to the previous 12 seconds for 1k parses!).
int _objectCount = 0;
public void Put(string key, object value)
{
int localCount = 0;
for (int i = 0; i < pArr.Length; i++)
{
if (pArr[i] != null)
{
localCount++;
if (pArr[i].key == key)
{
pArr[i] = new Paar(key, value);
return;
}
}
if (localCount == _objectCount)
{
return;
}
}
for (int i = 0; i < pArr.Length; i++)
{
if (pArr[i] == null)
{
pArr[i] = new Paar(key, value);
_objectCount++;
return;
}
else if (i >= pArr.Length)
{
throw new Exception("All slots full");
}
}
}

Comparing rapidly-changing string values to find frequent occurrences

My problem should be quite simple. I have a random generated string that changes multiple times per second. I want to return 1 if it appears x times consecutively.
My current code:
string s; //this is the generated string
int checker = 0;
string[] s_list = null;
if( cheaker == 0)
{
s_list[0] = s;
}
else if( cheaker == 1)
{
s_list[1] = s;
}
checker++;
if(s_list[0] == s_list[1]) return 1;
My problem is that I want to be able to change the amount of x times if appears and like this it will generate tons of code if the x is too big.
Do you think putting the current string into an array of string and compare them is the best way? There should be a better implementation.
To make the code generic for any given X, you should keep last X strings and check whether all they are equal, e.g.:
List<string> list = new List<string>();
if (list.Count >= X)
{
list.RemoveAt(0);
}
list.Add(newString);
return list.Count >= X && list.Any(s => s == list[0]);
I assume s_list is an array where you store all the generations of the string
string s;
string[] s_list;
// Your logic that would generate s and store it in s_list
// ...
// ...
int required_amount = 10; // whatever X amount you want
int current_sequence = 0;
// It's important to start at 1, and not 0,
// as you compare to the previous entry each time
for(int i = 1; i < s_list.Lenght; i++ )
{
if( s_list[i] == s_list[i-1] )
{
current_sequence++;
if(current_sequence >= required_amount)
{
return 1;
}
}
else
{
current_sequence = 0;
}
}

C# Concatenate strings or array of chars

I'm facing a problem while developing an application.
Basically,
I have a fixed string, let's say "IHaveADream"
I now want to user to insert another string, for my purpose of a fixed length, and then concatenate every character of the fixed string with every character of the string inserted by the user.
e.g.
The user inserts "ByeBye"
then the output would be:
"IBHyaevBeyAeDream".
How to accomplish this?
I have tried with String.Concat and String.Join, inside a for statement, with no luck.
One memory-efficient option is to use a string builder, since both the original string and the user input could potentially be rather large. As mentioned by Kris, you can initialize your StringBuilder capacity to the combined length of both strings.
void Main()
{
var start = "IHaveADream";
var input = "ByeBye";
var sb = new StringBuilder(start.Length + input.Length);
for (int i = 0; i < start.Length; i++)
{
sb.Append(start[i]);
if (input.Length >= i + 1)
sb.Append(input[i]);
}
sb.ToString().Dump();
}
This only safely accounts for the input string being shorter or equal in length to the starting string. If you had a longer input string, you'd want to take the longer length as the end point for your for loop iteration and check that each array index is not out of bounds.
void Main()
{
var start = "IHaveADream";
var input = "ByeByeByeByeBye";
var sb = new StringBuilder(start.Length + input.Length);
var length = start.Length >= input.Length ? start.Length : input.Length;
for (int i = 0; i < length; i++)
{
if (start.Length >= i + 1)
sb.Append(start[i]);
if (input.Length >= i + 1)
sb.Append(input[i]);
}
sb.ToString().Dump();
}
You can create an array of characters and then re-combine them in the order you want.
char[] chars1 = "IHaveADream".ToCharArray();
char[] chars2 = "ByeBye".ToCharArray();
// you can create a custom algorithm to handle
// different size strings.
char[] c = new char[17];
c[0] = chars1[0];
c[1] = chars2[0];
...
c[13] = chars1[10];
string s = new string(c);
var firstString = "Ihaveadream";
var secondString = "ByeBye";
var stringBuilder = new StringBuilder();
for (int i = 0; i< firstString.Length; i++) {
stringBuilder .Append(str[i]);
if (i < secondString.Length) {
stringBuilder .Append(secondStr[i]);
}
}
var result = stringBuilder.ToString();
If you don't care much about memory usage or perfomance you can just use:
public static string concatStrings(string value, string value2)
{
string result = "";
int i = 0;
for (i = 0; i < Math.Max(value.Length, value2.Length) ; i++)
{
if (i < value.Length) result += value[i].ToString();
if (i < value2.Length) result += value2[i].ToString();
}
return result;
}
Usage:
string conststr = "IHaveADream";
string input = "ByeBye";
var result = ConcatStrings(conststr, input);
Console.WriteLine(result);
Output: IBHyaevBeyAeDream
P.S.
Just checked perfomance of both methods (with strBuilder and simple cancatenation) and it appears to be that both of this methods take same time to execute (if you have just one operation). The main reason for it is that string builder take considerable time to initialize while with use of concatenation we don't need that.
But in case if you have to process something like 1500 strings then it's different story and string builder is more of an option.
For 100 000 method executions it showed 85 (str buld) vs 22 (concat) ms respectively.
My Code

Improve string parse performance

Before we start, I am aware of the term "premature optimization". However the following snippets have proven to be an area where improvements can be made.
Alright. We currently have some network code that works with string based packets. I am aware that using strings for packets is stupid, crazy and slow. Sadly, we don't have any control over the client and so have to use strings.
Each packet is terminated by \0\r\n and we currently use a StreamReader/Writer to read individual packets from the stream. Our main bottleneck comes from two places.
Firstly: We need to trim that nasty little null-byte off the end of the string. We currently use code like the following:
line = await reader.ReadLineAsync();
line = line.Replace("\0", ""); // PERF this allocates a new string
if (string.IsNullOrWhiteSpace(line))
return null;
var packet = ClientPacket.Parse(line, cl.Client.RemoteEndPoint);
As you can see by that cute little comment, we have a GC performance issue when trimming the '\0'. There are numerous different ways you could trim a '\0' off the end of a string, but all will result in the same GC hammering we get. Because all string operations are immutable, they result in a new string object being created. As our server handles 1000+ connections all communicating at around 25-40 packets per second (its a game server), this GC matter is becoming an issue. So here comes my first question: What is a more efficient way of trimming that '\0' off the end of our string? By efficient I don't only mean speed, but also GC wise (ultimately I'd like a way to get rid of it without creating a new string object!).
Our second issue also stems from GC land. Our code looks somewhat like the following:
private static string[] emptyStringArray = new string[] { }; // so we dont need to allocate this
public static ClientPacket Parse(string line, EndPoint from)
{
const char seperator = '|';
var first_seperator_pos = line.IndexOf(seperator);
if (first_seperator_pos < 1)
{
return new ClientPacket(NetworkStringToClientPacketType(line), emptyStringArray, from);
}
var name = line.Substring(0, first_seperator_pos);
var type = NetworkStringToClientPacketType(name);
if (line.IndexOf(seperator, first_seperator_pos + 1) < 1)
return new ClientPacket(type, new string[] { line.Substring(first_seperator_pos + 1) }, from);
return new ClientPacket(type, line.Substring(first_seperator_pos + 1).Split(seperator), from);
}
(Where NetworkStringToClientPacketType is simply a big switch-case block)
As you can see we already do a few things to handle GC. We reuse a static "empty" string and we check for packets with no parameters. My only issue here is that we are using Substring a lot, and even chain a Split on the end of a Substring. This leads to (for an average packet) almost 20 new string objects being created and 12 being disposed of EACH PACKET. This causes a lot of performance issues when load increases anything over 400 users (we gotz fast ram :3)
Has anyone had an experience with this sort of thing before or could give us some pointers into what to look into next? Maybe some magical classes or some nifty pointer magic?
(PS. StringBuilder doesn't help as we aren't building strings, we are generally splitting them.)
We currently have some ideas based on an index based system where we store the index and length of each parameter rather than splitting them. Thoughts?
A few other things. Decompiling mscorlib and browsing the string class code, it seems to me like IndexOf calls are done via P/Invoke, which would mean they have added overhead for each call, correct me if I'm wrong? Would it not be faster to implement an IndexOf manually using a char[] array?
public int IndexOf(string value, int startIndex, int count, StringComparison comparisonType)
{
...
return TextInfo.IndexOfStringOrdinalIgnoreCase(this, value, startIndex, count);
...
}
internal static int IndexOfStringOrdinalIgnoreCase(string source, string value, int startIndex, int count)
{
...
if (TextInfo.TryFastFindStringOrdinalIgnoreCase(4194304, source, startIndex, value, count, ref result))
{
return result;
}
...
}
...
[DllImport("QCall", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool InternalTryFindStringOrdinalIgnoreCase(int searchFlags, string source, int sourceCount, int startIndex, string target, int targetCount, ref int foundIndex);
Then we get to String.Split which ends up calling Substring itself (somewhere along the line):
// string
private string[] InternalSplitOmitEmptyEntries(int[] sepList, int[] lengthList, int numReplaces, int count)
{
int num = (numReplaces < count) ? (numReplaces + 1) : count;
string[] array = new string[num];
int num2 = 0;
int num3 = 0;
int i = 0;
while (i < numReplaces && num2 < this.Length)
{
if (sepList[i] - num2 > 0)
{
array[num3++] = this.Substring(num2, sepList[i] - num2);
}
num2 = sepList[i] + ((lengthList == null) ? 1 : lengthList[i]);
if (num3 == count - 1)
{
while (i < numReplaces - 1)
{
if (num2 != sepList[++i])
{
break;
}
num2 += ((lengthList == null) ? 1 : lengthList[i]);
}
break;
}
i++;
}
if (num2 < this.Length)
{
array[num3++] = this.Substring(num2);
}
string[] array2 = array;
if (num3 != num)
{
array2 = new string[num3];
for (int j = 0; j < num3; j++)
{
array2[j] = array[j];
}
}
return array2;
}
Thankfully Substring looks fast (and efficient!):
private unsafe string InternalSubString(int startIndex, int length, bool fAlwaysCopy)
{
if (startIndex == 0 && length == this.Length && !fAlwaysCopy)
{
return this;
}
string text = string.FastAllocateString(length);
fixed (char* ptr = &text.m_firstChar)
{
fixed (char* ptr2 = &this.m_firstChar)
{
string.wstrcpy(ptr, ptr2 + (IntPtr)startIndex, length);
}
}
return text;
}
After reading this answer here, I'm thinking a pointer based solution could be found... Thoughts?
Thanks.
You could "cheat" and work at the Encoder level...
public class UTF8NoZero : UTF8Encoding
{
public override Decoder GetDecoder()
{
return new MyDecoder();
}
}
public class MyDecoder : Decoder
{
public Encoding UTF8 = new UTF8Encoding();
public override int GetCharCount(byte[] bytes, int index, int count)
{
return UTF8.GetCharCount(bytes, index, count);
}
public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
{
int count2 = UTF8.GetChars(bytes, byteIndex, byteCount, chars, charIndex);
int i, j;
for (i = charIndex, j = charIndex; i < charIndex + count2; i++)
{
if (chars[i] != '\0')
{
chars[j] = chars[i];
j++;
}
}
for (int k = j; k < charIndex + count2; k++)
{
chars[k] = '\0';
}
return count2 + (i - j);
}
}
Note that this cheat is based on the fact that StreamReader.ReadLineAsync uses only the GetChars(). We remove the '\0' in the temporary buffer char[] buffer used by StreamReader.ReadLineAsync.

How do you perform string replacement on just a subsection of a string?

I'd like an efficient method that would work something like this
EDIT: Sorry I didn't put what I'd tried before. I updated the example now.
// Method signature, Only replaces first instance or how many are specified in max
public int MyReplace(ref string source,string org, string replace, int start, int max)
{
int ret = 0;
int len = replace.Length;
int olen = org.Length;
for(int i = 0; i < max; i++)
{
// Find the next instance of the search string
int x = source.IndexOf(org, ret + olen);
if(x > ret)
ret = x;
else
break;
// Insert the replacement
source = source.Insert(x, replace);
// And remove the original
source = source.Remove(x + len, olen); // removes original string
}
return ret;
}
string source = "The cat can fly but only if he is the cat in the hat";
int i = MyReplace(ref source,"cat", "giraffe", 8, 1);
// Results in the string "The cat can fly but only if he is the giraffe in the hat"
// i contains the index of the first letter of "giraffe" in the new string
The only reason I'm asking is because my implementation I'd imagine getting slow with 1,000s of replaces.
How about:
public static int MyReplace(ref string source,
string org, string replace, int start, int max)
{
if (start < 0) throw new System.ArgumentOutOfRangeException("start");
if (max <= 0) return 0;
start = source.IndexOf(org, start);
if (start < 0) return 0;
StringBuilder sb = new StringBuilder(source, 0, start, source.Length);
int found = 0;
while (max-- > 0) {
int index = source.IndexOf(org, start);
if (index < 0) break;
sb.Append(source, start, index - start).Append(replace);
start = index + org.Length;
found++;
}
sb.Append(source, start, source.Length - start);
source = sb.ToString();
return found;
}
it uses StringBuilder to avoid lots of intermediate strings; I haven't tested it rigorously, but it seems to work. It also tries to avoid an extra string when there are no matches.
To start, try something like this:
int count = 0;
Regex.Replace(source, Regex.Escape(literal), (match) =>
{
return (count++ > something) ? "new value" : match.Value;
});
To replace only the first match:
private string ReplaceFirst(string source, string oldString, string newString)
{
var index = source.IndexOf(oldString);
var begin = source.Substring(0, index);
var end = source.Substring(index + oldString.Length);
return begin + newString + end;
}
You have a bug in that you will miss the item to replace if it is in the beginning.
change these lines;
int ret = start; // instead of zero, or you ignore the start parameter
// Find the next instance of the search string
// Do not skip olen for the first search!
int x = i == 0 ? source.IndexOf(org, ret) : source.IndexOf(org, ret + olen);
Also your routine does 300 thousand replaces a second on my machine. Are you sure this will be a bottleneck?
And just found that your code also has an issue if you replace larger texts by smaller texts.
This code is 100% faster if you have four replaces and around 10% faster with one replacement (faster when compared with the posted original code). It uses the specified start parameter and works when replacing larger texts by smaller texts.
Mark Gravells solution is (no offense ;-) 60% slower as the original code and it also returns another value.
// Method signature, Only replaces first instance or how many are specified in max
public static int MyReplace(ref string source, string org, string replace, int start, int max)
{
var ret = 0;
int x = start;
int reps = 0;
int l = source.Length;
int lastIdx = 0;
string repstring = "";
while (x < l)
{
if ((source[x] == org[0]) && (reps < max) && (x >= start))
{
bool match = true;
for (int y = 1; y < org.Length; y++)
{
if (source[x + y] != org[y])
{
match = false;
break;
}
}
if (match)
{
repstring += source.Substring(lastIdx, x - lastIdx) + replace;
ret = x;
x += org.Length - 1;
reps++;
lastIdx = x + 1;
// Done?
if (reps == max)
{
source = repstring + source.Substring(lastIdx);
return ret;
}
}
}
x++;
}
if (ret > 0)
{
source = repstring + source.Substring(lastIdx);
}
return ret;
}

Categories