Replace only 'n' occurences of a substring in a string in C# - c#

I have a input string like -
abbdabab
How to replace only the 2nd, 3rd and subsequent occurances of the substring "ab" with any random string like "x" keeping the original string intact. Example in this case -
1st Output - xbdabab 2nd Output - abbdxab 3rd Output - abbdabx and so on...
I have tried using Regex like -
int occCount = Regex.Matches("abbdabab", "ab").Count;
if (occCount > 1)
{
for (int i = 1; i <= occCount; i++)
{
Regex regReplace = new Regex("ab");
string modifiedValue = regReplace.Replace("abbdabab", "x", i);
//decodedMessages.Add(modifiedValue);
}
}
Here I am able to get the 1st output when the counter i value is 1 but not able to get the subsequent results. Is there any overloaded Replace method which could achieve this ? Or Can anyone help me in pointing where I might have gone wrong?

You can try IndexOf instead of regular expressions:
string source = "abbdabab";
string toFind = "ab";
string toSet = "X";
for (int index = source.IndexOf(toFind);
index >= 0;
index = source.IndexOf(toFind, index + 1)) {
string result = source.Substring(0, index) +
toSet +
source.Substring(index + toFind.Length);
Console.WriteLine(result);
}
Outcome:
Xbdabab
abbdXab
abbdabX

You can use a StringBuilder:
string s = "abbdabab";
var matches = Regex.Matches(s, "ab");
StringBuilder sb = new StringBuilder(s);
var m = matches[0]; // 0 for first output, 1 for second output, and so on
sb.Remove(m.Index, m.Length);
sb.Insert(m.Index, "x");
var result = sb.ToString();
Console.WriteLine(result);

You may use a dynamically built regex to be used with regex.Replace directly:
var s = "abbdabab";
var idx = 1; // First = 1, Second = 2
var search = "ab";
var repl = "x";
var pat = new Regex($#"(?s)((?:{search}.*?){{{idx-1}}}.*?){search}"); // ((?:ab.*?){0}.*?)ab
Console.WriteLine(pat.Replace(s, $"${{1}}{repl}", 1));
See the C# demo
The pattern will look like ((?:ab.*?){0}.*?)ab and will match
(?s) - RegexOptions.Singleline to make . also match newlines
((?:ab.*?){0}.*?) - Group 1 (later, this value will be put back into the result with ${1} backreference)
(?:ab.*?){0} - 0 occurrences of ab followed with any 0+ chars as few as possible
.*? - any 0+ chars as few as possible
ab - the search string/pattern.
The last argument to pat.Replace is 1, so that only the first occurrence could be replaced.
If search is a literal text, you need to use var search = Regex.Escape("a+b");.
If the repl can have $, add repl = repl.Replace("$", "$$");.

Related

Replace Only Multiples Of three in c#

How can I replace only multiples of 3 in C#? Say for example I had the string "000100000", and I wanted "000" to be replaced with "+" but only every group of three characters. Additional condition: the groups should be changed starting from the end:, e.g. for "000100000" it should output "+100+".
You can just use a regular expression for this.
(0{3}(?!0+))
This uses a negative lookahead to make sure there aren't any other zeros after a group of three 0s - in other words, for a sequence of an arbitrary number of 0s, it'll only match the last 3.
You can modify this if you want to do something subtly different looking lookaheads and lookbehinds.
I suggest using regular expressions, e.g.:
string source = "000100000";
// "+100+"
string result = Regex.Replace(
source,
"0{3,}",
match => new string('0', match.Length % 3) + new string('+', match.Length / 3));
Tests:
001 -> 001
0001 -> +1
000100 -> +100
0001000 -> +1+
00010000 -> +10+
000100000 -> +100+
0001000000 -> +1++
You can do this with Substring:
string strReplace = "000100000";
//Store your string on StringBuilder to edit the string
StringBuilder sb = new StringBuilder();
sb.Append("+");
sb.Append(strReplace.Substring(0, 3)); //Use substring, 0 is the start of index and 3 is the length as your requirement
sb.Append("+");
sb.Append(strReplace.Substring(3, 3));
sb.Append("+");
sb.Append(strReplace.Substring(6, 3));
sb.Append("+");
strReplace = sb.ToString(); //Finally replace your string instance with your result
Or by for loop but this time instead of using substring, we use Char array to get every char in your string:
string strReplace = "000100000";
char[] chReplace = strReplace.ToCharArray();
StringBuilder sb = new StringBuilder();
for (int x = 0; x <= 8; x++)
{
if (x == 0 || x == 3 || x == 6 || x == 9)
{
sb.Append("+");
sb.Append(chReplace[x]);
}
else
{
sb.Append(chReplace[x]);
}
}
sb.Append("+");
strReplace = sb.ToString();
Okay, a bunch of these answers are addressing detecting groups of 3 '0's. Here's an answer that deals with groups of 3 anythings (reading the string in groups of three characters):
string GroupsOfThree(string str)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i + 2 < str.Length; i += 3)
{
string sub = str.Substring(i, 3);
if (sub.All(c => c == sub[0]))
sb.Append("+");
else
sb.Append(sub);
}
return sb.ToString();
}
You can use a replace regular expression.
"[0]{3}|[1]{3}"
The above Regular Expression can be use like below in C#:
string k = "000100000";
Regex pattern = new Regex("[0]{3}|[1]{3}");
pattern.Replace(k, "+");
reversing the string before you replace and after solves your problem.
something like:
string ReplaceThreeZeros(string text)
{
var reversed = new string(text.Reverse().ToArray());
var replaced = reversed.Replace("000","+");
return new string(replaced.Reverse().ToArray());
}

How can I capitalize every third letter of a string in C#?

How can I capitalize every third letter of a string in C#?
I loop through the whole string with a for loop, but I can't think of the sequence right now.
I suspect you just want something like this:
// String is immutable; copy to a char[] so we can modify that in-place
char[] chars = input.ToCharArray();
for (int i = 0; i < chars.Length; i += 3)
{
chars[i] = char.ToUpper(chars[i]);
}
// Now construct a new String from the modified character array
string output = new string(chars);
That assumes you want to start capitalizing from the first letter, so "abcdefghij" would become "AbcDefGhiJ". If you want to start capitalizing elsewhere, just change the initial value of i.
var s = "Lorem ipsum";
var foo = new string(s
.Select((c, i) => (i + 1) % 3 == 0 ? Char.ToUpper(c) : c)
.ToArray());
You are already looping through the characters inside a string? Then add a counter, increment it on each iteration, and if it is 3, then use .ToUpper(currentCharacter) to make it upper case. Then reset your counter.
You could just use a regular expression.
If the answer is every third char then you want
var input = "sdkgjslgjsklvaswlet";
var regex = new Regex("(..)(.)");
var replacement = regex.Replace(input, delegate(Match m)
{
return m.Groups[1].Value + m.Groups[2].Value.ToUpper();
});
If you want every third character, but starting with the first you want:
var input = "sdkgjslgjsklvaswlet";
var regex = new Regex("(.)(..)");
var replacement = regex.Replace(input, delegate(Match m)
{
return m.Groups[1].Value.ToUpper() + m.Groups[2].Value;
});
If you want a loop, you can convert to a character array first, so you can alter the values.
For every third character:
var x = input.ToCharArray();
for (var i = 2; i <x.Length; i+=3) {
x[i] = char.ToUpper(x[i]);
}
var replacement = new string(x);
For every third character from the beginning:
var x = input.ToCharArray();
for (var i = 0; i <x.Length; i+=3) {
x[i] = char.ToUpper(x[i]);
}
var replacement = new string(x);

Change in string some part, but without one part - where are numbers

For example I have such string:
ex250-r-ninja-08-10r_
how could I change it to such string?
ex250 r ninja 08-10r_
as you can see I change all - to space, but didn't change it where I have XX-XX part... how could I do such string replacement in c# ? (also string could be different length)
I do so for -
string correctString = errString.Replace("-", " ");
but how to left - where number pattern XX-XX ?
You can use regular expressions to only perform substitutions in certain cases. In this case, you want to perform a substitution if either side of the dash is a non-digit. That's not quite as simple as it might be, but you can use:
string ReplaceSomeHyphens(string input)
{
string result = Regex.Replace(input, #"(\D)-", "${1} ");
result = Regex.Replace(result, #"-(\D)", " ${1}");
return result;
}
It's possible that there's a more cunning way to do this in a single regular expression, but I suspect that it would be more complicated too :)
A very uncool approach using a StringBuilder. It'll replace all - with space if the two characters before and the two characters behind are not digits.
StringBuilder sb = new StringBuilder();
for (int i = 0; i < text.Length; i++)
{
bool replace = false;
char c = text[i];
if (c == '-')
{
if (i < 2 || i >= text.Length - 2) replace = true;
else
{
bool leftDigit = text.Substring(i - 2, 2).All(Char.IsDigit);
bool rightDigit = text.Substring(i + 1, 2).All(Char.IsDigit);
replace = !leftDigit || !rightDigit;
}
}
if (replace)
sb.Append(' ');
else
sb.Append(c);
}
Since you say you won't have hyphens at the start of your string then you need to capture every occurrence of - that is preceded by a group of characters which contains at least one letter and zero or many numbers. To achieve this, use positive lookbehind in your regex.
string strRegex = #"(?<=[a-z]+[0-9]*)-";
Regex myRegex = new Regex(strRegex, RegexOptions.IgnoreCase | RegexOptions.Multiline);
string strTargetString = #"ex250-r-ninja-08-10r_";
string strReplace = #" ";
return myRegex.Replace(strTargetString, strReplace);
Here are the results:

C# RegEx string extraction

I have a string:
"ImageDimension=655x0;ThumbnailDimension=0x0".
I have to extract first number ("655" string) coming in between "ImageDimension=" and first occurrence of "x" ;
and need extract second number ("0" string) coming after first "x" occurring after "ImageDimension=" string. Similar with third and fourth numbers.
Can this be done with regex ("ImageDimension=? x ?;ThumbnailDimension=? x ?") and how ? Instead of clumsy substrings and indexof ? Thank you!
My solution which is not nice :
String configuration = "ImageDimension=655x0;ThumbnailDimension=0x0";
String imageDim = configuration.Substring(0, configuration.IndexOf(";"));
int indexOfEq = imageDim.IndexOf("=");
int indexOfX = imageDim.IndexOf("x");
String width1 = imageDim.Substring(indexOfEq+1, indexOfX-indexOfEq-1);
String height1 = imageDim.Substring(imageDim.IndexOf("x") + 1);
String thumbDim = configuration.Substring(configuration.IndexOf(";") + 1);
indexOfEq = thumbDim.IndexOf("=");
indexOfX = thumbDim.IndexOf("x");
String width2 = imageDim.Substring(indexOfEq + 1, indexOfX - indexOfEq-1);
String height2 = imageDim.Substring(imageDim.IndexOf("x") + 1);
This will get each of the values into separate ints for you:
string text = "ImageDimension=655x0;ThumbnailDimension=0x0";
Regex pattern = new Regex(#"ImageDimension=(?<imageWidth>\d+)x(?<imageHeight>\d+);ThumbnailDimension=(?<thumbWidth>\d+)x(?<thumbHeight>\d+)");
Match match = pattern.Match(text);
int imageWidth = int.Parse(match.Groups["imageWidth"].Value);
int imageHeight = int.Parse(match.Groups["imageHeight"].Value);
int thumbWidth = int.Parse(match.Groups["thumbWidth"].Value);
int thumbHeight = int.Parse(match.Groups["thumbHeight"].Value);
var groups = Regex.Match(input,#"ImageDimension=(\d+)x(\d+);ThumbnailDimension=(\d+)x(\d+)").Groups;
var x1= groups[1].Value;
var y1= groups[2].Value;
var x2= groups[3].Value;
var y2= groups[4].Value;
var m = Regex.Match(str,#"(\d+).(\d+).*?(\d+).(\d+)");
m.Groups[1].Value; // 655 ....
(\d+)
Get the first set of one or more digits. and store it as the first captured group after the entire match
.
Match any character
(\d+)
Get the next set of one or more digits. and store it as the second captured group after the entire match
.*?
match and number of any characters in a non greedy fashion.
(\d+)
Get the next set of one or more digits. and store it as the third captured group after the entire match
(\d+)
Get the next set of one or more digits. and store it as the fourth captured group after the entire match
Since a lot of people already gave you what you wanted, I will contribute with something else. Regexes are hard to read and error prone. Maybe a little less verbose than your implementation but more straightforward and friendly than using regex:
private static Dictionary<string, string> _extractDictionary(string str)
{
var query = from name_value in str.Split(';') // Split by ;
let arr = name_value.Split('=') // ... then by =
select new {Name = arr[0], Value = arr[1]};
return query.ToDictionary(x => x.Name, y => y.Value);
}
public static void Main()
{
var str = "ImageDimension=655x0;ThumbnailDimension=0x0";
var dic = _extractDictionary(str);
foreach (var key_value in dic)
{
var key = key_value.Key;
var value = key_value.Value;
Console.WriteLine("Value of {0} is {1}.", key, value.Substring(0, value.IndexOf("x")));
}
}
Sure, it's pretty easy. The regex pattern you're looking for is:
^ImageDimension=(\d+)x0;.+$
The first group in the match is the number you want.

Replace placeholders in order

I have a part of a URL like this:
/home/{value1}/something/{anotherValue}
Now i want to replace all between the brackets with values from a string-array.
I tried this RegEx pattern: \{[a-zA-Z_]\} but it doesn't work.
Later (in C#) I want to replace the first match with the first value of the array, second with the second.
Update: The /'s cant be used to separate. Only the placeholders {...} should be replaced.
Example: /home/before{value1}/and/{anotherValue}
String array: {"Tag", "1"}
Result: /home/beforeTag/and/1
I hoped it could works like this:
string input = #"/home/before{value1}/and/{anotherValue}";
string pattern = #"\{[a-zA-Z_]\}";
string[] values = {"Tag", "1"};
MatchCollection mc = Regex.Match(input, pattern);
for(int i, ...)
{
mc.Replace(values[i];
}
string result = mc.GetResult;
Edit:
Thank you Devendra D. Chavan and ipr101,
both solutions are greate!
You can try this code fragment,
// Begin with '{' followed by any number of word like characters and then end with '}'
var pattern = #"{\w*}";
var regex = new Regex(pattern);
var replacementArray = new [] {"abc", "cde", "def"};
var sourceString = #"/home/{value1}/something/{anotherValue}";
var matchCollection = regex.Matches(sourceString);
for (int i = 0; i < matchCollection.Count && i < replacementArray.Length; i++)
{
sourceString = sourceString.Replace(matchCollection[i].Value, replacementArray[i]);
}
[a-zA-Z_] describes a character class. For words, you'll have to add * at the end (any number of characters within a-zA-Z_.
Then, to have 'value1' captured, you'll need to add number support : [a-zA-Z0-9_]*, which can be summarized with: \w*
So try this one : {\w*}
But for replacing in C#, string.Split('/') might be easier as Fredrik proposed. Have a look at this too
You could use a delegate, something like this -
string[] strings = {"dog", "cat"};
int counter = -1;
string input = #"/home/{value1}/something/{anotherValue}";
Regex reg = new Regex(#"\{([a-zA-Z0-9]*)\}");
string result = reg.Replace(input, delegate(Match m) {
counter++;
return "{" + strings[counter] + "}";
});
My two cents:
// input string
string txt = "/home/{value1}/something/{anotherValue}";
// template replacements
string[] str_array = { "one", "two" };
// regex to match a template
Regex regex = new Regex("{[^}]*}");
// replace the first template occurrence for each element in array
foreach (string s in str_array)
{
txt = regex.Replace(txt, s, 1);
}
Console.Write(txt);

Categories

Resources