I want to add space between every 3 characters in a string in C#, but count from right to left.
For example :
11222333 -> 11 222 333
Answer by #Jimi from comments (will delete if they post their own)
var YourString = "11222333";
var sb = new StringBuilder(YourString);
for (int i = sb.Length -3; i >= 0; i -= 3)
sb.Insert(i, ' ');
return sb.ToString();
The benefit of this algorithm appears to be that you are working backwards through the string and therefore only moving a certain amount on each run, rather than the whole string.
If you are trying to format a string as a number according to some locale conventions you can use the NumberFormat class to set how you want a number to be formatted as a string
So for example
string input = "11222333";
NumberFormatInfo currentFormat = new NumberFormatInfo();
currentFormat.NumberGroupSeparator = " ";
if(Int32.TryParse(input, NumberStyles.None, currentFormat, out int result))
{
string output = result.ToString("N0", currentFormat);
Console.WriteLine(output); // 11 222 333
}
The following recursive function would do the job:
string space3(string s)
{
int len3 = s.Length - 3;
return (len <= 0) ? s
: (space3(s.Substring(0, len3)) + " " + s.Substring(len3));
}
C# 8.0 introduced string ranges. Ranges allow for a more compact form:
string space3(string s)
{
return (s.Length <= 3) ? s
: (space3(s[..^3]) + " " + s[^3..]);
}
Using Regex.Replace:
string input = "11222333";
string result = Regex.Replace( input, #"\d{3}", #" $0", RegexOptions.RightToLeft );
Demo and detailed explanation of RegEx pattern at regex101.
tl;dr: Match groups of 3 digits from right to left and replace them by space + the 3 digits.
The most efficient algorithm I can come up with is the following:
var sb = new StringBuilder(YourString.Length + YourString.Length / 3 + 1);
if (YourString.Length % 3 > 0)
{
sb.Append(YourString, 0, YourString.Length % 3);
sb.Append(' ');
}
for (var i = YourString.Length % 3; i < YourString.Length; i += 3)
{
sb.Append(YourString, i, 3);
sb.Append(' ');
}
return sb.ToString();
We first assign a StringBuilder of the correct size.
Then we check to see if we need to append the first one or two characters. Then we loop the rest.
dotnetfiddle
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("$", "$$");.
I have a string which represents byte array, inside of it I have several groups of numbers (usually 5): which are encoded as 0x30..0x39 (codes for 0..9 digits). Before and after each number I have a space (0x20 code).
Examples:
"E5-20-32-36-20-E0" // "32-36" encodes number "26", notice spaces: "20"
"E5-20-37-20-E9" // "37" encodes number "7"
"E5-20-38-20-E7-E4-20-37-35-20-E9" // two numbers: "8" (from "38") and "75" (from "37-35")
I want to find out all these groups and reverse digits in the encoded numbers:
8 -> 8
75 -> 57
123 -> 321
Desired outcome:
"E5-20-32-36-20-E0" -> "E5-20-36-32-20-E0"
"E5-20-37-20-E9" -> "E5-20-37-20-E9"
"E5-20-37-38-39-20-E9" -> "E5-20-39-38-37-20-E9"
"E5-20-38-39-20-E7-E4-20-37-35-20-E9" -> "E5-20-39-38-20-E7-E4-20-35-37-20-E9"
I have the data inside a List \ String \ Byte[] - so maybe there is a way to do it ?
Thanks,
It's unclear (from the original question) what do you want to do with the the digits; let's extract a custom method for you to implement it. As an example, I've implemented reverse:
32 -> 32
32-36 -> 36-32
36-32-37 -> 37-32-36
36-37-38-39 -> 39-38-37-36
Code:
// items: array of digits codes, e.g. {"36", "32", "37"}
//TODO: put desired transformation here
private static IEnumerable<string> Transform(string[] items) {
// Either terse Linq:
// return items.Reverse();
// Or good old for loop:
string[] result = new string[items.Length];
for (int i = 0; i < items.Length; ++i)
result[i] = items[items.Length - i - 1];
return result;
}
Now we can use regular expressions (Regex) to extract all the digit sequencies and replace them with transformed ones:
using System.Text.RegularExpressions;
...
string input = "E5-20-36-32-37-20-E0";
string result = Regex
.Replace(input,
#"(?<=20\-)3[0-9](\-3[0-9])*(?=\-20)",
match => string.Join("-", Transform(match.Value.Split('-'))));
Console.Write($"Before: {input}{Environment.NewLine}After: {result}";);
Outcome:
Before: E5-20-36-32-37-20-E0
After: E5-20-37-32-36-20-E0
Edit: In case reverse is the only desired transformation, the code can be simplified by dropping Transform and adding Linq:
using System.Linq;
using System.Text.RegularExpressions;
...
string input = "E5-20-36-32-37-20-E0";
string result = Regex
.Replace(input,
#"(?<=20\-)3[0-9](\-3[0-9])*(?=\-20)",
match => string.Join("-", match.Value.Split('-').Reverse()));
More tests:
private static string MySolution(string input) {
return Regex
.Replace(input,
#"(?<=20\-)3[0-9](\-3[0-9])*(?=\-20)",
match => string.Join("-", Transform(match.Value.Split('-'))));
}
...
string[] tests = new string[] {
"E5-20-32-36-20-E0",
"E5-20-37-20-E9",
"E5-20-37-38-39-20-E9",
"E5-20-38-39-20-E7-E4-20-37-35-20-E9",
};
string report = string.Join(Environment.NewLine, tests
.Select(test => $"{test,-37} -> {MySolution(test)}"));
Console.Write(report);
Outcome:
E5-20-32-36-20-E0 -> E5-20-36-32-20-E0
E5-20-37-20-E9 -> E5-20-37-20-E9
E5-20-37-38-39-20-E9 -> E5-20-39-38-37-20-E9
E5-20-38-39-20-E7-E4-20-37-35-20-E9 -> E5-20-39-38-20-E7-E4-20-35-37-20-E9
Edit 2: Regex explanation (see https://www.regular-expressions.info/lookaround.html for details):
(?<=20\-) - must appear before the match: "20-" ("-" escaped with "\")
3[0-9](\-3[0-9])* - match itself (what we are replacing in Regex.Replace)
(?=\-20) - must appear after the match "-20" ("-" escaped with "\")
Let's have a look at match part 3[0-9](\-3[0-9])*:
3 - just "3"
[0-9] - character (digit) within 0-9 range
(\-3[0-9])* - followed by zero or more - "*" - groups of "-3[0-9]"
I'm not sure but I guess the length can change and you just want to reorder in reverse order just the numbers. so a possible way is:
Put the string in 2 arrays (so they are the same)
Iterate through one of them to locate begin and end o fthe number area
Go from end-area to begin-area in first array and write to the second from begin-area to end-area
Edit: not really tested, i just wrote that quickly:
string input = "E5-20-36-32-37-20-E0";
string[] array1 = input.Split('-');
string[] array2 = input.Split('-');
int startIndex = -1;
int endIndex = -1;
for (int i= 0; i < array1.Length; ++i)
{
if (array1[i] == "20")
{
if (startIndex < 0)
{
startIndex = i + 1;
}
else
{
endIndex = i - 1;
}
}
}
int pos1 = startIndex;
int pos2 = endIndex;
for (int j=0; j < (endIndex- startIndex + 1); ++j)
{
array1[pos1] = array2[pos2];
pos1++;
pos2--;
}
If you would be clear about how you want to process the numbers, it would be easier to provide a solution.
Do you want to swap them randomly?
Do you want to reverse order?
Do you want to swap every second number with the number before?
Do you want to swap ...
you can try the following (for reversing the numbers)
string hex = "E5-20-36-32-20-E0"; // this is your input string
// split the numbers by '-' and generate list out of it
List<string> hexNumbers = new List<string>();
hexNumbers.AddRange(hex.Split('-'));
// find start and end of the numbers that should be swapped
int startIndex = hexNumbers.IndexOf("20");
int endIndex = hexNumbers.LastIndexOf("20");
string newHex = "";
// add the part in front of the numbers that should be reversed
for (int i = 0; i <= startIndex; i++) newHex += hexNumbers[i] + "-";
// reverse the numbers
for (int i = endIndex-1; i > startIndex; i--) newHex += hexNumbers[i] + "-";
// add the part behind the numbers that should be reversed
for (int i = endIndex; i < hexNumbers.Count-1; i++) newHex += hexNumbers[i] + "-";
newHex += hexNumbers.Last();
If the start and the end is always the same, this can be fairly simplified into 4 lines of code:
string[] hexNumbers = hex.Split('-');
string newHex = "E5-20-";
for (int i = hexNumbers.Count() - 3; i > 1; i--) newHex += hexNumbers[i] + "-";
newHex += "20-E0";
Results:
"E5-20-36-32-20-E0" -> "E5-20-32-36-20-E0"
"E5-20-36-32-37-20-E0" -> "E5-20-32-37-36-20-E0"
"E5-20-36-12-18-32-20-E0" -> "E5-20-32-18-12-36-20-E0"
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:
I have a string which contains binary digits. How to separate string after each 8 digit?
Suppose the string is:
string x = "111111110000000011111111000000001111111100000000";
I want to add a separator like ,(comma) after each 8 character.
output should be :
"11111111,00000000,11111111,00000000,11111111,00000000,"
Then I want to send it to a list<> last 8 char 1st then the previous 8 chars(excepting ,) and so on.
How can I do this?
Regex.Replace(myString, ".{8}", "$0,");
If you want an array of eight-character strings, then the following is probably easier:
Regex.Split(myString, "(?<=^(.{8})+)");
which will split the string only at points where a multiple of eight characters precede it.
Try this:
var s = "111111110000000011111111000000001111111100000000";
var list = Enumerable
.Range(0, s.Length/8)
.Select(i => s.Substring(i*8, 8));
var res = string.Join(",", list);
There's another Regex approach:
var str = "111111110000000011111111000000001111111100000000";
# for .NET 4
var res = String.Join(",",Regex.Matches(str, #"\d{8}").Cast<Match>());
# for .NET 3.5
var res = String.Join(",", Regex.Matches(str, #"\d{8}")
.OfType<Match>()
.Select(m => m.Value).ToArray());
...or old school:
public static List<string> splitter(string in, out string csv)
{
if (in.length % 8 != 0) throw new ArgumentException("in");
var lst = new List<string>(in/8);
for (int i=0; i < in.length / 8; i++) lst.Add(in.Substring(i*8,8));
csv = string.Join(",", lst); //This we want in input order (I believe)
lst.Reverse(); //As we want list in reverse order (I believe)
return lst;
}
Ugly but less garbage:
private string InsertStrings(string s, int insertEvery, char insert)
{
char[] ins = s.ToCharArray();
int length = s.Length + (s.Length / insertEvery);
if (ins.Length % insertEvery == 0)
{
length--;
}
var outs = new char[length];
long di = 0;
long si = 0;
while (si < s.Length - insertEvery)
{
Array.Copy(ins, si, outs, di, insertEvery);
si += insertEvery;
di += insertEvery;
outs[di] = insert;
di ++;
}
Array.Copy(ins, si, outs, di, ins.Length - si);
return new string(outs);
}
String overload:
private string InsertStrings(string s, int insertEvery, string insert)
{
char[] ins = s.ToCharArray();
char[] inserts = insert.ToCharArray();
int insertLength = inserts.Length;
int length = s.Length + (s.Length / insertEvery) * insert.Length;
if (ins.Length % insertEvery == 0)
{
length -= insert.Length;
}
var outs = new char[length];
long di = 0;
long si = 0;
while (si < s.Length - insertEvery)
{
Array.Copy(ins, si, outs, di, insertEvery);
si += insertEvery;
di += insertEvery;
Array.Copy(inserts, 0, outs, di, insertLength);
di += insertLength;
}
Array.Copy(ins, si, outs, di, ins.Length - si);
return new string(outs);
}
If I understand your last requirement correctly (it's not clear to me if you need the intermediate comma-delimited string or not), you could do this:
var enumerable = "111111110000000011111111000000001111111100000000".Batch(8).Reverse();
By utilizing morelinq.
Here my two little cents too. An implementation using StringBuilder:
public static string AddChunkSeparator (string str, int chunk_len, char separator)
{
if (str == null || str.Length < chunk_len) {
return str;
}
StringBuilder builder = new StringBuilder();
for (var index = 0; index < str.Length; index += chunk_len) {
builder.Append(str, index, chunk_len);
builder.Append(separator);
}
return builder.ToString();
}
You can call it like this:
string data = "111111110000000011111111000000001111111100000000";
string output = AddChunkSeparator(data, 8, ',');
One way using LINQ:
string data = "111111110000000011111111000000001111111100000000";
const int separateOnLength = 8;
string separated = new string(
data.Select((x,i) => i > 0 && i % separateOnLength == 0 ? new [] { ',', x } : new [] { x })
.SelectMany(x => x)
.ToArray()
);
I did it using Pattern & Matcher as following way:
fun addAnyCharacter(input: String, insertion: String, interval: Int): String {
val pattern = Pattern.compile("(.{$interval})", Pattern.DOTALL)
val matcher = pattern.matcher(input)
return matcher.replaceAll("$1$insertion")
}
Where:
input indicates Input string. Check results section.
insertion indicates Insert string between those characters. For example comma (,), start(*), hash(#).
interval indicates at which interval you want to add insertion character.
input indicates Input string. Check results section. Check results section; here I've added insertion at every 4th character.
Results:
I/P: 1234XXXXXXXX5678 O/P: 1234 XXXX XXXX 5678
I/P: 1234567812345678 O/P: 1234 5678 1234 5678
I/P: ABCDEFGHIJKLMNOP O/P: ABCD EFGH IJKL MNOP
Hope this helps.
As of .Net 6, you can simply use the IEnumerable.Chunk method (Which splits elements of a sequence into chunks) then reconcatenate the chunks using String.Join.
var text = "...";
string.Join(',', text.Chunk(size: 6).Select(x => new string(x)));
This is much faster without copying array (this version inserts space every 3 digits but you can adjust it to your needs)
public string GetString(double valueField)
{
char[] ins = valueField.ToString().ToCharArray();
int length = ins.Length + (ins.Length / 3);
if (ins.Length % 3 == 0)
{
length--;
}
char[] outs = new char[length];
int i = length - 1;
int j = ins.Length - 1;
int k = 0;
do
{
if (k == 3)
{
outs[i--] = ' ';
k = 0;
}
else
{
outs[i--] = ins[j--];
k++;
}
}
while (i >= 0);
return new string(outs);
}
For every 1 character, you could do this one-liner:
string.Join(".", "1234".ToArray()) //result: 1.2.3.4
If you intend to create your own function to acheive this without using regex or pattern matching methods, you can create a simple function like this:
String formatString(String key, String seperator, int afterEvery){
String formattedKey = "";
for(int i=0; i<key.length(); i++){
formattedKey += key.substring(i,i+1);
if((i+1)%afterEvery==0)
formattedKey += seperator;
}
if(formattedKey.endsWith("-"))
formattedKey = formattedKey.substring(0,formattedKey.length()-1);
return formattedKey;
}
Calling the mothod like this
formatString("ABCDEFGHIJKLMNOPQRST", "-", 4)
Would result in the return string as this
ABCD-EFGH-IJKL-MNOP-QRST
A little late to the party, but here's a simplified LINQ expression to break an input string x into groups of n separated by another string sep:
string sep = ",";
int n = 8;
string result = String.Join(sep, x.InSetsOf(n).Select(g => new String(g.ToArray())));
A quick rundown of what's happening here:
x is being treated as an IEnumerable<char>, which is where the InSetsOf extension method comes in.
InSetsOf(n) groups characters into an IEnumerable of IEnumerable -- each entry in the outer grouping contains an inner group of n characters.
Inside the Select method, each group of n characters is turned back into a string by using the String() constructor that takes an array of chars.
The result of Select is now an IEnumerable<string>, which is passed into String.Join to interleave the sep string, just like any other example.
I am more than late with my answer but you can use this one:
static string PutLineBreak(string str, int split)
{
for (int a = 1; a <= str.Length; a++)
{
if (a % split == 0)
str = str.Insert(a, "\n");
}
return str;
}