在VB.NET中一行代码内替换字符串中的多个字符。

14
使用 VB.NET,我想在一行代码中替换字符串中的一段字符范围。 例如:
Dim charsToReplace as string = "acegi"
Dim stringToBeReplaced as string = "abcdefghijklmnop"

charsToReplace.ToArray().ForEach(Function (c) stringTobeReplaced = stringTobeReplaced.Replace(c, ""))

然而,这种方法不起作用。

以下方法可以实现,但我不想将字符串作为类级变量:

 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

这可行吗?


这是一个“应该直接问准确问题而不是改述”的例子。具体来说,我实际上有一个字符串,它基本上是一系列由空格分隔的单词。我有一个单词数组,想从字符串中剥离出来,因此我认为foreach循环将是可能/有用的。当以此方式提出(不同的)问题时,正则表达式是不适合的。所以基本上: dim words() as string = ("the", "brown", "lazy") dim sentence as string = "the quick brown fox jumps" results="quick fox jumps" 我的希望是words.ForEach(Function (w) sentence.Replace(w, "")) - hitch
8个回答

28

如果我理解正确,您想从字符串中剥离一系列字符。这需要使用正则表达式。

Console.WriteLine(Regex.Replace("abcdefghijklmnop", "[acegi]", string.Empty))

(你需要导入 System.Text.RegularExpressions)


如果经常使用该方法,它的性能如何? - serhio
@serhio:正则表达式实际上是用于字符串操作的。无论你使用什么来处理字符串,正则表达式都可以更快地完成,并且使用更少的资源。 - Simon Dugré
@SimonDugré,正如我之前回答的那样(比你的评论早),情况恰恰相反。正则表达式要慢得多。 - JDC

8

正则表达式方法是最适合的,但我真正想说的是:

请为了维护开发者的爱好,不要沉迷于将其简化为一行代码。一个方法调用才是你的真正目标,如果你最终只是将许多调用堆叠在一行中,并宣称这是一行代码,那么你会自食恶果。


我的主要目标不是为了开发方面将其压缩成一行,而是出于“心血来潮因为它不像我想象的那样工作,我想弄清楚如何做到”的目的... :) - hitch
5
给维护开发人员加1 - 我已经经历过了,有那种头疼的感觉!=) - Rob

7

我一开始并不相信Bittercode所说的LINQ比正则表达式更高效,于是我进行了一些测试以确保这点。

以下是三个例子:

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

结果如下:

结果:

性能测试结果


因此,使用字符串替换的 for 循环的性能优于所有其他方法。

因此,我会创建一个字符串对象的扩展函数。

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

那么你可以在一行中使用这个函数,写法简单易懂:
_textToStrip.ReplaceAll(_invalidChars, CChar(String.Empty))

编辑(十年后):

我再次需要尽可能快地完成这个任务。
这一次我编写了一个真正的性能测试(benchmarkdotnet)。
我使用了 net6.0。

代码可在 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), ""));
        }


    }


}

结果:

方法 平均值 误差 标准偏差
LinqToArray 635.2 纳秒 12.20 纳秒 11.42 纳秒
ForEach 119.0 纳秒 1.58 纳秒 1.40 纳秒
Regexer 392.0 纳秒 7.38 纳秒 8.50 纳秒
Hasher 402.0 纳秒 6.04 纳秒 5.65 纳秒
分割法 109.8 纳秒 1.84 纳秒 1.72 纳秒
Aggregate 136.6 纳秒 2.62 纳秒 2.45 纳秒

Linq 方法涉及在无效字符数组中进行线性查找。如果使用的是 HashSet(Of Char) 呢? - Craig
1
@craig 使用 char 的哈希集合,使得最差的方法稍微好了一点(请看我的编辑)。最好的方法是使用分割方法。 - JDC

1

String类有一个replace方法可以实现这个功能。你可以这样使用它:

YourString = YourString.Replace("OldValue", "NewValue")

我可能没有表达清楚,但我想替换字符串中每个字符的每个实例。例如: chars = "ace" longString = "abcdeabcdeabcde"结果应该是 "bdbdbd"replace 方法无法做到这一点。 - hitch
2
你实际上可以在同一语句中多次使用 Replace:myDate2 = Date.Now.ToString("s").Replace(":", "-").Replace("T", " ") - Gary Heath

1

我推荐Jon Galloway的方法,正则表达式是适当的方法,未来的开发人员也会感谢你 :) - 虽然使用Linq解决这个问题也不难。以下是一些(未经测试的)C#代码:

string stringToBeReplaced = "abcdefghijklmnop";
string charsToReplace = "acegi";
stringToBeReplaced = new String(stringToBeReplaced.Where(c => !charsToReplace.Any(rc => c == rc)).ToArray());

如果性能是一个问题,我怀疑这段代码可能会比正则表达式等效的代码略微更好。


0

如果您真的想使用该代码,重复行语句的最佳方式是什么:

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

例如:如果您输入了:012ALP456HA90BET678,则输出将是:ALPHABET

欢迎来到stackoverflow。请查看我对你的问题所做的编辑,以便你知道如何更好地提问。 - Brett

0
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

两个数组必须同时增长,您可以替换简单字符和/或字符串,但每个数组中的元素数量必须相同。希望这很清楚,也希望这很有用... - Diprotask

0
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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接