2012-06-28 38 views
8

Có phương pháp nào khác nhanh hơn làm như thế này không?Nhanh hơn String.Replace()

private void EscapeStringSequence(ref string data) 
{ 
    data = data.Replace("\\", "\\\\"); // Backslash 
    data = data.Replace("\r", "\\r"); // Carriage return 
    data = data.Replace("\n", "\\n"); // New Line 
    data = data.Replace("\a", "\\a"); // Vertical tab 
    data = data.Replace("\b", "\\b"); // Backspace 
    data = data.Replace("\f", "\\f"); // Formfeed 
    data = data.Replace("\t", "\\t"); // Horizontal tab 
    data = data.Replace("\v", "\\v"); // Vertical tab 
    data = data.Replace("\"", "\\\""); // Double quotation mark 
    data = data.Replace("'", "\\'"); // Single quotation mark 
} 

- Edited (Thêm lời giải thích) -
Q1: Có một lý do tại sao bạn cần để tăng tốc độ nó lên? Nó có gây ra một vấn đề lớn không?
Phần này được sử dụng trong dự án này: http://mysqlbackuprestore.codeplex.com/
Tôi sẽ lặp lại nhiều chuỗi độ dài khác nhau thành hàm này lặp lại. Toàn bộ quá trình mất khoảng 6-15 giây để hoàn thành cho hàng triệu hàng. Có một phần khác có liên quan quá. Tôi đang cố gắng tăng tốc mọi phần.

Q2: Hiện giờ chậm như thế nào?
OK, tôi sẽ ghi lại thời gian chính xác được sử dụng và đăng tại đây. Tôi sẽ quay lại sau. (sẽ đăng kết quả vào ngày mai)

Cập nhật 29-06-2012
Xin chào các bạn. Tôi đã chạy thử. Đây là kết quả:

Speed ​​Test: String.Replace() - đo bằng mili giây
Test 1: 26.749,7531 ms
thử nghiệm 2: 27.063,438 ms
thử nghiệm 3: 27.753,8884 ms
trung bình: 27.189,0265 ms
tốc độ: 100%

Speed ​​Test: Foreach Char và Nối - đo bằng mili giây
Test 1: 8468,4547 ms
thử nghiệm 2: 8348,8527 ms
thử nghiệm 3: 8353,6476 ms
trung bình: 8390,3183 ms
Tốc độ: 224% < nhanh
================== =================
Cập nhật - Bài kiểm tra tiếp theo (Vòng khác)
=================== ================
------
Kiểm tra thay thế tốc độ chuỗi.
Test 1: 26.535,6466
thử nghiệm 2: 26.379,6464
thử nghiệm 3: 26.379,6463
trung bình: 26431,6464333333
Tốc độ: 100%
------
thử nghiệm Foreach Char Chuỗi Nối.
Test 1: 8502,015
thử nghiệm 2: 8517,6149
thử nghiệm 3: 8595,6151
trung bình: 8538,415
Tốc độ: 309,56%
------
thử nghiệm Foreach Char Chuỗi Nối (Fix Chiều dài StringBuilder).
Kiểm tra 1: 8314.8146
Kiểm tra 2: 8330.4147
thử nghiệm 3: 8346,0146
trung bình: 8.330,41463333333
Tốc độ: 317,29%


Kết luận:
Sử dụng Foreach Char Loop và Nối là nhanh hơn so với String.Replace().

Cảm ơn bạn rất nhiều bạn.

--------
Dưới đây là các mã mà tôi sử dụng để chạy thử nghiệm: (edited)

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.Write("Press any key to continue..."); 
      Console.ReadKey(); 
      Console.Write("\r\nProcess started."); 
      Test(); 
      Console.WriteLine("Done."); 
      Console.Read(); 
     } 

     public static Random random = new Random((int)DateTime.Now.Ticks); 

     public static string RandomString(int size) 
     { 
      StringBuilder sb = new StringBuilder(); 
      char ch; 
      for (int i = 0; i < size; i++) 
      { 
       ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))); 
       sb.Append(ch); 
      } 
      return sb.ToString(); 
     } 

     public static void Test() 
     { 
      string text = "\\_\r\n\a\b\f\t\v\"'" + RandomString(2000) + "\\_\r\n\a\b\f\t\v\"'" + RandomString(2000); 

      List<TimeSpan> lstTimeUsed = new List<TimeSpan>(); 

      int target = 100000; 

      for (int i = 0; i < 3; i++) 
      { 
       DateTime startTime = DateTime.Now; 
       for (int j = 0; j < target; j++) 
       { 
        if (j.ToString().EndsWith("000")) 
        { 
         Console.Clear(); 
         Console.WriteLine("Test " + i.ToString()); 
         Console.WriteLine(j.ToString() + " of " + target.ToString()); 
        } 

        string data = text; 

        data = data.Replace("\\", "\\\\"); // Backslash 
        data = data.Replace("\r", "\\r"); // Carriage return 
        data = data.Replace("\n", "\\n"); // New Line 
        data = data.Replace("\a", "\\a"); // Vertical tab 
        data = data.Replace("\b", "\\b"); // Backspace 
        data = data.Replace("\f", "\\f"); // Formfeed 
        data = data.Replace("\t", "\\t"); // Horizontal tab 
        data = data.Replace("\v", "\\v"); // Vertical tab 
        data = data.Replace("\"", "\\\""); // Double quotation mark 
        data = data.Replace("'", "\\'"); // Single quotation mark 

       } 
       DateTime endTime = DateTime.Now; 
       TimeSpan ts = endTime - startTime; 
       lstTimeUsed.Add(ts); 
      } 

      double t1 = lstTimeUsed[0].TotalMilliseconds; 
      double t2 = lstTimeUsed[1].TotalMilliseconds; 
      double t3 = lstTimeUsed[2].TotalMilliseconds; 
      double tOri = (t1 + t2 + t3)/3; 

      System.IO.TextWriter tw = new System.IO.StreamWriter("D:\\test.txt", true); 
      tw.WriteLine("------"); 
      tw.WriteLine("Test Replace String Speed. Test Time: " + DateTime.Now.ToString()); 
      tw.WriteLine("Test 1: " + t1.ToString()); 
      tw.WriteLine("Test 2: " + t2.ToString()); 
      tw.WriteLine("Test 3: " + t3.ToString()); 
      tw.WriteLine("Average: " + tOri.ToString()); 
      tw.WriteLine("Speed: 100%"); 
      tw.Close(); 

      lstTimeUsed = new List<TimeSpan>(); 

      for (int i = 0; i < 3; i++) 
      { 
       DateTime startTime = DateTime.Now; 
       for (int j = 0; j < target; j++) 
       { 
        if (j.ToString().EndsWith("000")) 
        { 
         Console.Clear(); 
         Console.WriteLine("Test " + i.ToString()); 
         Console.WriteLine(j.ToString() + " of " + target.ToString()); 
        } 

        string data = text; 

        var builder = new StringBuilder(); 
        foreach (var ch in data) 
        { 
         switch (ch) 
         { 
          case '\\': 
          case '\r': 
          case '\n': 
          case '\a': 
          case '\b': 
          case '\f': 
          case '\t': 
          case '\v': 
          case '\"': 
          case '\'': 
           builder.Append('\\'); 
           break; 
          default: 
           break; 
         } 
         builder.Append(ch); 
        } 

       } 
       DateTime endTime = DateTime.Now; 
       TimeSpan ts = endTime - startTime; 
       lstTimeUsed.Add(ts); 
      } 

      t1 = lstTimeUsed[0].TotalMilliseconds; 
      t2 = lstTimeUsed[1].TotalMilliseconds; 
      t3 = lstTimeUsed[2].TotalMilliseconds; 

      tw = new System.IO.StreamWriter("D:\\test.txt", true); 
      tw.WriteLine("------"); 
      tw.WriteLine("Test Foreach Char String Append. Test Time: " + DateTime.Now.ToString()); 
      tw.WriteLine("Test 1: " + t1.ToString()); 
      tw.WriteLine("Test 2: " + t2.ToString()); 
      tw.WriteLine("Test 3: " + t3.ToString()); 
      tw.WriteLine("Average: " + ((t1 + t2 + t3)/3).ToString()); 
      tw.WriteLine("Speed: " + ((tOri)/((t1 + t2 + t3)/3) * 100).ToString("0.00") + "%"); 
      tw.Close(); 

      lstTimeUsed = new List<TimeSpan>(); 

      for (int i = 0; i < 3; i++) 
      { 
       DateTime startTime = DateTime.Now; 
       for (int j = 0; j < target; j++) 
       { 
        if (j.ToString().EndsWith("000")) 
        { 
         Console.Clear(); 
         Console.WriteLine("Test " + i.ToString()); 
         Console.WriteLine(j.ToString() + " of " + target.ToString()); 
        } 

        string data = text; 

        var builder = new StringBuilder(data.Length + 20); 
        foreach (var ch in data) 
        { 
         switch (ch) 
         { 
          case '\\': 
          case '\r': 
          case '\n': 
          case '\a': 
          case '\b': 
          case '\f': 
          case '\t': 
          case '\v': 
          case '\"': 
          case '\'': 
           builder.Append('\\'); 
           break; 
          default: 
           break; 
         } 
         builder.Append(ch); 
        } 

       } 
       DateTime endTime = DateTime.Now; 
       TimeSpan ts = endTime - startTime; 
       lstTimeUsed.Add(ts); 
      } 

      t1 = lstTimeUsed[0].TotalMilliseconds; 
      t2 = lstTimeUsed[1].TotalMilliseconds; 
      t3 = lstTimeUsed[2].TotalMilliseconds; 

      tw = new System.IO.StreamWriter("D:\\test.txt", true); 
      tw.WriteLine("------"); 
      tw.WriteLine("Test Foreach Char String Append (Fix StringBuilder Length). Test Time: " + DateTime.Now.ToString()); 
      tw.WriteLine("Test 1: " + t1.ToString()); 
      tw.WriteLine("Test 2: " + t2.ToString()); 
      tw.WriteLine("Test 3: " + t3.ToString()); 
      tw.WriteLine("Average: " + ((t1 + t2 + t3)/3).ToString()); 
      tw.WriteLine("Speed: " + ((tOri)/((t1 + t2 + t3)/3) * 100).ToString("0.00") + "%"); 
      tw.Close(); 

     } 
    } 
} 
+3

Hiện giờ chậm như thế nào? –

+0

có thể trùng lặp [cách nhanh nhất để thay thế chuỗi trong một mẫu] (http://stackoverflow.com/questions/959940/fastest-way-to-replace-string-in-a-template) – adatapost

+0

Đưa chuỗi vào một StringBuilder và sau đó sử dụng StringBuilder.Replace có thể nhanh hơn. Viết vòng lặp một lần của riêng bạn để tạo chuỗi kết quả sẽ nhanh hơn nhiều. – hatchet

Trả lời

11
var builder = new StringBuilder(data.Length + 20); 
    foreach (var ch in data) 
    { 
     switch (ch) 
     { 
     case '\\': 
     case '\r': 
     ... 
      builder.Append('\\'); 
      break; 
     } 
     builder.Append(ch); 
    } 
    return builder.ToString(); 
+1

Bạn có thể muốn chỉ định dung lượng ban đầu lớn hơn, bởi vì bạn đang thay thế các ký tự đơn bằng các chuỗi nhiều ký tự. – Blorgbeard

+0

Đẹp! .......... –

+2

Có thể được đơn giản hóa dọc theo các dòng: 'switch (ch) {case '\\': case '\ r': builder.Append ('\'); phá vỡ; } builder.Append (ch); ' – porges

1

Hãy thử sử dụng một loạt các StringBuilder gọi.

+0

Giả sử bạn có nghĩa là thay thế các cuộc gọi 'String.Append' bằng các cuộc gọi' StringBuilder.Append' - kiểm tra một chút tốt * chậm hơn * so với mã ban đầu của OP (30% đến 100% chậm hơn đối với tôi, tùy thuộc vào kích thước của chuỗi; một triệu lần lặp). Không chắc tại sao lại như thế. –