Reputation: 291
Using VB.NET I'd like to be able to replace a range of characters in a string in a single line of code.
I.e., something like:
Dim charsToReplace as string = "acegi"
Dim stringToBeReplaced as string = "abcdefghijklmnop"
charsToReplace.ToArray().ForEach(Function (c) stringTobeReplaced = stringTobeReplaced.Replace(c, ""))
However, this doesn't work.
The following does work, however I don't want the string to be a class level variable:
Sub Main()
Dim toReplace As String = "acegikmoq"
Console.WriteLine(mainString)
Dim chars As List(Of Char) = toReplace.ToList()
chars.ForEach(AddressOf replaceVal)
Console.WriteLine(mainString)
Console.ReadLine()
End Sub
Dim mainString As String = "this is my string that has values in it that I am going to quickly replace all of..."
Sub replaceVal(ByVal c As Char)
mainString = mainString.Replace(c, "")
End Sub
Can this be done?
Upvotes: 14
Views: 83282
Reputation: 1785
I didn't believe Bittercode as he said that LINQ would outperform regex. So I did a little test just to be sure.
Three examples of how to do this:
Dim _invalidChars As Char() = New Char() {"j"c, "a"c, "n"c}
Dim _textToStrip As String = "The quick brown fox jumps over the lazy dog"
Private Sub btnStripInvalidCharsLINQ_Click(sender As System.Object, e As System.EventArgs) Handles btnStripInvalidCharsLINQ.Click
Dim stripped As String = String.Empty
Dim sw As Stopwatch = Stopwatch.StartNew
For i As Integer = 0 To 10000
stripped = _textToStrip.Where(Function(c As Char) Not _invalidChars.Contains(c)).ToArray
Next
sw.Stop()
lblStripInvalidCharsLINQ.Text = _stripped & " - in " & sw.Elapsed.TotalMilliseconds & " ms"
End Sub
Private Sub btnStripInvalidCharsFOR_Click(sender As System.Object, e As System.EventArgs) Handles btnStripInvalidCharsFOR.Click
Dim stripped As String = String.Empty
Dim sw As Stopwatch = Stopwatch.StartNew
stripped = _textToStrip
For i As Integer = 0 To 10000
For Each c As Char In _invalidChars
stripped = stripped.Replace(c, "")
Next
Next
sw.Stop()
lblStipInvalidcharsFor.Text = stripped & " - in " & sw.Elapsed.TotalMilliseconds & " ms"
End Sub
Private Sub btnStripInvalidCharsREGEX_Click(sender As System.Object, e As System.EventArgs) Handles btnStripInvalidCharsREGEX.Click
Dim stripped As String = String.Empty
Dim sw As Stopwatch = Stopwatch.StartNew
For i As Integer = 0 To 10000
stripped = Regex.Replace(_textToStrip, "[" & New String(_invalidChars) & "]", String.Empty)
Next
sw.Stop()
lblStripInvalidCharsRegex.Text = stripped & " - in " & sw.Elapsed.TotalMilliseconds & " ms"
End Sub
The results:
So, the for loop with string.replace outperformes all the other methods.
Because of this I would make an extension function to the string object.
Module StringExtensions
<Extension()> _
Public Function ReplaceAll(ByVal InputValue As String, ByVal chars As Char(), replaceWith As Char) As String
Dim ret As String = InputValue
For Each c As Char In chars
ret = ret.Replace(c, replaceWith)
Next
Return ret
End Function
Then you could use this function nice and readably in one line:
_textToStrip.ReplaceAll(_invalidChars, CChar(String.Empty))
EDIT (10 years later):
I once again needed this to be as fast as possible.
I wrote a real performance test this time (benchmarkdotnet).
I used net6.0.
Code available in github: https://github.com/j-dc/stackoverflow_1332454
//[SimpleJob(RuntimeMoniker.Net462, baseline: true)]
//[SimpleJob(RuntimeMoniker.Net48)]
[SimpleJob(RuntimeMoniker.Net60)]
[RPlotExporter]
public class RemoveChars {
private static readonly char[] _invalidChars = new[] { 'j', 'a', 'n' };
private static readonly string _textToStrip = "The quick brown fox jumps over the lazy dog";
private static readonly HashSet<char> _invalidHash = new(new[] { 'j', 'a', 'n' });
[Benchmark]
public string Linq() {
return new string(_textToStrip.Where(x => !_invalidChars.Contains(x)).ToArray());
}
[Benchmark]
public string ForEach() {
string ret = _textToStrip;
foreach(char c in _invalidChars) {
ret = ret.Replace(Convert.ToString(c), "");
}
return ret;
}
[Benchmark]
public string Regexer() {
return Regex.Replace(_textToStrip, $"[{new string(_invalidChars) }]", string.Empty);
}
[Benchmark]
public string Hasher() {
return new string(_textToStrip.Where(x => _invalidHash.Contains(x)).ToArray());
}
[Benchmark]
public string Splitting() {
return string.Join(string.Empty, _textToStrip.Split(_invalidChars, StringSplitOptions.RemoveEmptyEntries));
}
[Benchmark]
public string Aggregate() {
return _invalidChars.Aggregate(_textToStrip, (c1, c2) => c1.Replace(Convert.ToString(c2), ""));
}
}
}
Results:
Method | Mean | Error | StdDev |
---|---|---|---|
LinqToArray | 635.2 ns | 12.20 ns | 11.42 ns |
ForEach | 119.0 ns | 1.58 ns | 1.40 ns |
Regexer | 392.0 ns | 7.38 ns | 8.50 ns |
Hasher | 402.0 ns | 6.04 ns | 5.65 ns |
Splitting | 109.8 ns | 1.84 ns | 1.72 ns |
Aggregate | 136.6 ns | 2.62 ns | 2.45 ns |
Upvotes: 7
Reputation: 11
Private Sub cmdTest_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdTest.Click
Dim s As String = "México Juárez índice recúrso dirección"
Dim arr() As String = {"á", "é", "í", "ó", "ú", "Ñ", "ñ"}
Dim rep() As String = {"a", "e", "i", "o", "u", "N", "n"}
Dim i As Integer = Nothing
For i = 0 To UBound(arr)
s = Replace(s, arr(i), rep(i))
Next
MsgBox(s)
End Sub
Upvotes: 0
Reputation: 5610
The String class has a replace method to do this. You can use it this way:
YourString = YourString.Replace("OldValue", "NewValue")
Upvotes: 1
Reputation: 1
Public Function SuperReplace(ByRef field As String, ByVal ReplaceString As String) As String
' Size this as big as you need... it is zero-based by default'
Dim ReplaceArray(4) As String
'Fill each element with the character you need to replace'
ReplaceArray(0) = "WARD NUMBER "
ReplaceArray(1) = "WN "
ReplaceArray(2) = "WARD NO "
ReplaceArray(3) = "WARD-"
ReplaceArray(4) = "WARD "
Dim i As Integer
For i = LBound(ReplaceArray) To UBound(ReplaceArray)
field = Replace(field, ReplaceArray(i), ReplaceString)
Next i
SuperReplace = field
End Function
Upvotes: 0
Reputation: 1
What is the best way to repeat the line statement if you really want to use that code:
Sub Main()
Dim myString As String = Nothing
Dim finalString As String = Nothing
Console.Write("Please enter a string: ") 'your free to put anything
myString = Console.ReadLine()
finalString = myString.Replace("0", "")
myString = finalString
finalString = myString.Replace("1", "")
myString = finalString
finalString = myString.Replace("2", "")
myString = finalString
finalString = myString.Replace("3", "")
myString = finalString
finalString = myString.Replace("4", "")
myString = finalString
finalString = myString.Replace("5", "")
myString = finalString
finalString = myString.Replace("6", "")
myString = finalString
finalString = myString.Replace("7", "")
myString = finalString
finalString = myString.Replace("8", "")
myString = finalString
finalString = myString.Replace("9", "")
Console.WriteLine(finalString)
Console.ReadLine()
End Sub
For example: if you typed: 012ALP456HA90BET678
the output would be: ALPHABET
.
Upvotes: 0
Reputation: 46366
The RegEx approach is the best suited, but what I really need to say is:
Please, for the love of maintenance developers, don't get hung-up on getting this down to 1 line of code. One method call is your real goal, if you end up just piling a bunch of calls into 1 line to say it's one-line then you're shooting yourself in the foot.
Upvotes: 8
Reputation: 12123
I recommend Jon Galloway's approach, a regular expression is the appropriate method, and future developers will thank you for it :) - though it's not a difficult problem to solve with Linq as well. Here's some (untested) C# code to do that:
string stringToBeReplaced = "abcdefghijklmnop";
string charsToReplace = "acegi";
stringToBeReplaced = new String(stringToBeReplaced.Where(c => !charsToReplace.Any(rc => c == rc)).ToArray());
I suspect this code will probably perform slightly better then the regex equivalent, if performance is an issue.
Upvotes: 1
Reputation: 53125
If I read this correctly, you're trying to strip a list of characters from a string. This is a good fit for a RegEx.
Console.WriteLine(Regex.Replace("abcdefghijklmnop", "[acegi]", string.Empty))
(you'll need to import System.Text.RegularExpressions)
Upvotes: 28