I have the following string:
string str = "***********4123";
I want the output as
**** ****** *4123
The following code is adding spaces after every 4 chars:
Regex.Replace(maskedString, ".{4}", "$0 ");
Is there any way I can add space after the 4th & 6th char?
CodePudding user response:
Working with capturing groups.
Transform to a new value with "{first group} {second group} {remaining}".
string str = "***********4123";
var replaceStr = Regex.Replace(str, @"(\*{4})(\*{6})(.*)", "$1 $2 $3");
CodePudding user response:
If you do not insist on using Regex, you can do:
using System;
public class Program
{
public static void Main()
{
string str = "***********4123";
var strSpan = str.AsSpan();
Console.WriteLine($"{strSpan[..4]} {strSpan[4..10]} {strSpan[10..]}");
}
}
Output:
**** ****** *4123
In action: https://dotnetfiddle.net/kKoRJb
Mind that for production, I'd add sanitychecks for the input.
- IsNullOrWhiteSpace
- Trim (maybe)
- Length underrun
Also: If you opt for Regex, consider precompiling it and caching. I did not run benchmarks of this solution against Regex, so you might want to do that if performace is critical here.
Update
So, I was intrigued and did a little Benchmark:
BenchmarkDotNet=v0.13.3, OS=Windows 10 (10.0.19044.2364/21H2/November2021Update) Intel Core i9-10885H CPU 2.40GHz, 1 CPU, 16 logical and 8 physical cores .NET SDK=7.0.101 [Host] : .NET 7.0.1 (7.0.122.56804), X64 RyuJIT AVX2 DefaultJob : .NET 7.0.1 (7.0.122.56804), X64 RyuJIT AVX2 | Method | N | Mean | Error | StdDev | Ratio | RatioSD | Allocated | Alloc Ratio | |----------------------- |------ |------------:|----------:|----------:|------:|--------:|----------:|------------:| | RegexVersionUncompiled | 1000 | 336.97 us | 6.616 us | 6.189 us | 7.79 | 0.21 | 62.52 KB | 1.00 | | RegexVersionCompiled | 1000 | 252.49 us | 4.904 us | 5.036 us | 5.85 | 0.19 | 62.52 KB | 1.00 | | SpanVersion | 1000 | 43.15 us | 0.812 us | 0.834 us | 1.00 | 0.00 | 62.52 KB | 1.00 | | StringInsertVersion | 1000 | 33.27 us | 0.655 us | 0.852 us | 0.78 | 0.03 | 117.21 KB | 1.87 | | | | | | | | | | | | RegexVersionUncompiled | 10000 | 3,254.56 us | 54.729 us | 48.515 us | 7.55 | 0.20 | 625.03 KB | 1.00 | | RegexVersionCompiled | 10000 | 2,424.43 us | 39.463 us | 32.953 us | 5.62 | 0.14 | 625.03 KB | 1.00 | | SpanVersion | 10000 | 432.77 us | 8.456 us | 9.048 us | 1.00 | 0.00 | 625.02 KB | 1.00 | | StringInsertVersion | 10000 | 429.94 us | 4.070 us | 3.178 us | 1.00 | 0.02 | 1171.9 KB | 1.87 | // * Hints * Outliers Benchmark.SpanVersion: Default -> 4 outliers were removed (45.56 us..71.61 us) Benchmark.RegexVersionUncompiled: Default -> 1 outlier was removed, 4 outliers were detected (3.16 ms..3.18 ms, 3.37 ms) Benchmark.RegexVersionCompiled: Default -> 2 outliers were removed, 5 outliers were detected (2.36 ms..2.39 ms, 2.48 ms, 3.42 ms) Benchmark.StringInsertVersion: Default -> 3 outliers were removed (441.17 us..460.36 us) // * Legends * N : Value of the 'N' parameter Mean : Arithmetic mean of all measurements Error : Half of 99.9% confidence interval StdDev : Standard deviation of all measurements Ratio : Mean of the ratio distribution ([Current]/[Baseline]) RatioSD : Standard deviation of the ratio distribution ([Current]/[Baseline]) Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B) Alloc Ratio : Allocated memory ratio distribution ([Current]/[Baseline]) 1 us : 1 Microsecond (0.000001 sec)
Based on this code where I "stole" the Regex from Yong Shun's answer and the String.Insert Version from Hossein Sabziani' answer:
using BenchmarkDotNet.Attributes;
using Bogus;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace RegexBenchmark
{
[MemoryDiagnoser(false)]
public class Benchmark
{
[Params(1000, 10_000)]
public int N = 1000;
private readonly Regex _regex = new (@"(\*{4})(\*{6})(.*)", RegexOptions.Compiled);
private string[] _inputs;
[GlobalSetup]
public void Setup()
{
var faker = new Faker();
_inputs = Enumerable.Range(0, N).Select(_ => faker.Random.ReplaceNumbers("***********####")).ToArray();
}
[Benchmark]
public string[] RegexVersionUncompiled()
{
string[] result = new string[N];
for( int i = 0; i < N; i ) result[i] = Regex.Replace(_inputs[i], @"(\*{4})(\*{6})(.*)", "$1 $2 $3");
return result;
}
[Benchmark]
public string[] RegexVersionCompiled()
{
string[] result = new string[N];
for (int i = 0; i < N; i ) result[i] = _regex.Replace(_inputs[i], "$1 $2 $3");
return result;
}
[Benchmark]
public string[] SpanVersion()
{
string[] result = new string[N];
for (int i = 0; i < N; i )
{
var strSpan = _inputs[i].AsSpan();
result[i] = $"{strSpan[..4]} {strSpan[4..10]} {strSpan[10..]}";
}
return result;
}
[Benchmark]
public string[] StringInsertVersion()
{
string[] result = new string[N];
for (int i = 0; i < N; i )
{
result[i] = _inputs[i].Insert(4, " ").Insert(11, " ");
}
return result;
}
}
}
Interestingly: When I switched on display of GC Columns, it seems Regex puts less pressure on the Garbage Collection:
| Method | N | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Allocated | Alloc Ratio | |----------------------- |------ |------------:|----------:|----------:|------:|--------:|---------:|---------:|----------:|------------:| | RegexVersionUncompiled | 1000 | 329.92 us | 6.402 us | 8.547 us | 8.55 | 0.29 | 7.3242 | 1.4648 | 62.52 KB | 1.00 | | RegexVersionCompiled | 1000 | 244.21 us | 4.637 us | 4.962 us | 6.34 | 0.17 | 7.5684 | 1.7090 | 62.52 KB | 1.00 | | SpanVersion | 1000 | 38.60 us | 0.717 us | 0.670 us | 1.00 | 0.00 | 7.6294 | 1.8921 | 62.52 KB | 1.00 | | StringInsertVersion | 1000 | 32.69 us | 0.302 us | 0.267 us | 0.85 | 0.02 | 14.3433 | 3.5400 | 117.21 KB | 1.87 | | | | | | | | | | | | | | RegexVersionUncompiled | 10000 | 3,242.25 us | 61.809 us | 66.135 us | 7.50 | 0.09 | 74.2188 | 70.3125 | 625.03 KB | 1.00 | | RegexVersionCompiled | 10000 | 2,431.65 us | 47.894 us | 44.800 us | 5.64 | 0.13 | 74.2188 | 70.3125 | 625.03 KB | 1.00 | | SpanVersion | 10000 | 431.01 us | 5.069 us | 4.741 us | 1.00 | 0.00 | 76.1719 | 75.6836 | 625.02 KB | 1.00 | | StringInsertVersion | 10000 | 429.69 us | 7.117 us | 5.943 us | 1.00 | 0.02 | 142.5781 | 142.0898 | 1171.9 KB | 1.87 |
And considering the scaling, I'd probably still go with the Span Solution:
| Method | N | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Gen2 | Allocated | Alloc Ratio | |----------------------- |------- |-------------:|-----------:|-------------:|------:|--------:|----------:|---------:|---------:|------------:|------------:| | RegexVersionUncompiled | 1000 | 333.54 us | 6.403 us | 6.288 us | 7.69 | 0.15 | 7.3242 | 1.4648 | - | 62.52 KB | 1.00 | | RegexVersionCompiled | 1000 | 239.71 us | 4.601 us | 4.519 us | 5.52 | 0.14 | 7.5684 | 1.7090 | - | 62.52 KB | 1.00 | | SpanVersion | 1000 | 43.35 us | 0.412 us | 0.365 us | 1.00 | 0.00 | 7.6294 | 1.8921 | - | 62.52 KB | 1.00 | | StringInsertVersion | 1000 | 34.18 us | 0.523 us | 0.489 us | 0.79 | 0.01 | 14.3433 | 3.5400 | - | 117.21 KB | 1.87 | | | | | | | | | | | | | | | RegexVersionUncompiled | 10000 | 3,343.72 us | 66.047 us | 90.406 us | 6.85 | 0.21 | 74.2188 | 70.3125 | - | 625.03 KB | 1.00 | | RegexVersionCompiled | 10000 | 2,450.42 us | 31.348 us | 29.323 us | 5.00 | 0.10 | 74.2188 | 70.3125 | - | 625.03 KB | 1.00 | | SpanVersion | 10000 | 490.05 us | 6.722 us | 6.288 us | 1.00 | 0.00 | 76.1719 | 75.6836 | - | 625.02 KB | 1.00 | | StringInsertVersion | 10000 | 436.04 us | 5.316 us | 4.973 us | 0.89 | 0.02 | 142.5781 | 142.0898 | - | 1171.9 KB | 1.87 | | | | | | | | | | | | | | | RegexVersionUncompiled | 100000 | 40,730.47 us | 793.225 us | 1,058.932 us | 3.39 | 0.12 | 846.1538 | 769.2308 | 230.7692 | 6251.31 KB | 1.00 | | RegexVersionCompiled | 100000 | 32,578.02 us | 645.500 us | 1,163.969 us | 2.74 | 0.14 | 937.5000 | 906.2500 | 281.2500 | 6251.14 KB | 1.00 | | SpanVersion | 100000 | 12,016.15 us | 237.602 us | 300.491 us | 1.00 | 0.00 | 968.7500 | 953.1250 | 312.5000 | 6250.24 KB | 1.00 | | StringInsertVersion | 100000 | 25,158.93 us | 372.056 us | 329.818 us | 2.09 | 0.06 | 1625.0000 | 968.7500 | 312.5000 | 11719.01 KB | 1.87 |
CodePudding user response:
you can use String.Insert(Int32, String) To add a string at a specific index
:
var result= str.Insert(4, " ").Insert(11, " ");
Console.WriteLine(result); //"**** ****** *4123"