Certainly someone will come up with a RegEx solution, which in theory is better what you're doing (generates multiple memory allocations unnecessarily and presses the GC), but for me to do in hand is unbeatable.
I used StringBuilder
to avoid multiple allocations. I converted to ToString()
at the end and there in WriteLine()
did not need it because it does automatic, but I left because in your code you need to do the conversion.
The basic rule would be to scan the entire string and go copying each character, could even use LINQ, filtering when it is not a digit, and swap for ;
(I understood that anything other than a digit should convert, but the question does not make it so clear). So far it's easy, the problem is that you can not repeat ;
if it is already present. Then you have to set up a state machine.
I created a control variable that indicates whether the last character parsed is a digit. I start considering it is.
Whenever it is a digit and the previous one was not a digit it should concatenate the ;
, after all if it was an irregular character before and now I will start digit, I need to mark with the special character chosen. And obviously if it's a digit I have to say that the current one is sse, so in the next step the algorithm knows what to do.
When it is not a digit it is better to do nothing, after all you have to disappear with this character, it can not be shown. The only action is to identify that it is not a digit in the control variable.
The secret is to kill every invalid character without exception, and before you start concatenating a sequence of digits (it may even be a single one in the sequence), put the chosen special separator character, but never as soon as it starts.
To create a state machine you have to think like an employee. What decision to make with each character being analyzed. It's how a compiler works.
If I understood the rule correctly the code would be this (you can encapsulate in a generic method:
using static System.Console;
using System.Text;
public class Program {
public static void Main() {
var hs = "/4587 / 5458/";
var texto = new StringBuilder(hs.Length);
var digito = true;
foreach (var chr in hs) {
if (char.IsDigit(chr)) {
if (!digito) texto.Append(';');
texto.Append(chr);
digito = true;
} else digito = false;
}
WriteLine(texto.ToString());
}
}
See running on .NET Fiddle . And no Coding Ground . Also put it in GitHub for future reference .
You might want to further optimize with the new Span<T>
, but I will not risk this complication for you.