2012-02-13 77 views
8

Tôi chỉ tự hỏi cách dễ nhất để thay thế một chuỗi ký tự phải được thay thế sau đó là gì.Thay thế các ký tự không hợp lệ của một chuỗi có ký tự không hợp lệ

Ví dụ:

var str = "[Hello World]"; 
//enclose all occurences of [ and ] with brackets[] 
str = str.Replace("[","[[]").Replace("]","[]]"); 
  • Kết quả mong muốn: [[]Hello World[]]
  • Kết quả thực tế: [[[]]Hello World[]]

Lý do là rõ ràng là thay thế thứ hai trên chuỗi đã sửa đổi.

Vậy làm cách nào để thay thế tất cả các lần xuất hiện của các ký tự "xấu" có các ký tự chứa ký tự "xấu"?


Đo nhanh tất cả các phương pháp đã cho thấy rằng StringBuilder là cách hiệu quả nhất.

tập 190kb (tất cả trong mili giây)

regexTime   40.5065 
    replaceTime   20.8891 
    stringBuilderTime 6.9776 

tập tin 7MB

regexTime   1209.3529   
    replaceTime   403.3985 
    stringBuilderTime 175.2583 

Bằng cách này, các StringBuilder cách tiếp cận trực tiếp từ John được gấp đôi nhanh nhưCách tiếp cậntừ Sehe.

Tôi đã thực hiện một phần mở rộng ra khỏi nó:

public static String EncloseChars(this string input, char[] charsToEnclose, String leftSide, String rightSide) { 
    if (charsToEnclose == null || leftSide == null || rightSide == null) 
     throw new ArgumentException("Invalid arguments for EncloseChars", charsToEnclose == null ? "charsToEnclose" : leftSide == null ? "leftSide" : "rightSide"); 
    Array.Sort(charsToEnclose); 
    StringBuilder sb = new StringBuilder(); 
    foreach (char c in input) { 
     if (Array.BinarySearch(charsToEnclose, c) > -1) 
      sb.Append(leftSide).Append(c).Append(rightSide); 
     else 
      sb.Append(c); 
    } 
    return sb.ToString(); 
} 

"[Hello World]".EncloseChars(new char[]{'[', ']'},"[","]"); 
+3

+1 Được đo độc đáo, Tim. –

Trả lời

5

Đây là cách rất uncool để thực hiện. Nhưng nó có lợi thế là được khá gần với foolproof, tôi nghĩ, và không sử dụng regex (trong trường hợp bạn không muốn sử dụng regex).

StringBuilder sb = new StringBuilder(); 
foreach (char c in str.ToCharArray()) { 
    if (c == '[' || c == ']') { 
     sb.Append('[' + c + ']'); 
    } 
    else { 
     sb.Append(c); 
    } 
} 
string result = sb.ToString(); 
+0

Cảm ơn. Thường thì cách uncool là tốt nhất/nhanh nhất. Không có vấn đề gì khi bị ẩn trong một phương thức mở rộng;) –

4

gì về:

str = str.Replace("[", "$1[$2") 
     .Replace("]", "$1]$2") 
     .Replace("$1", "[") 
     .Replace("$2", "]"); 
+2

Ý tưởng hay, sử dụng giá trị màn hình làm trung gian. – Oded

+4

Nhưng bạn nên kiểm tra xem chuỗi có chưa chứa các giá trị màn hình này hay không, hoặc điều tương tự lại xảy ra. Ví dụ: 'Hello [$ 1]' – Oliver

+0

Chỉnh sửa để thay thế giá trị màn hình + các ký tự thực tế trước khi thay thế các giá trị ký tự thực tế có thể khắc phục vấn đề của Oliver (mặc dù theo kiểu tường và thang), nhưng chi phí dễ đọc , Tôi nghĩ. –

1

Làm thế nào về:

char[] replacedChars = str.SelectMany(ch => 
            (ch == '[' ? new char[] {'[', '[', ']'} : 
            (ch == ']' ? new char[] {'[', ']', ']'} : 
            new char[] {ch}))).ToArray(); 
string replaced = new string(replacedChars); 

Lưu ý rằng điều này tránh được vấn đề nhiều vòng nhưng tạo ít nhất là nhiều mảng vì có các ký tự trong chuỗi đầu vào để nó có thể không tối ưu về hiệu suất.

+0

+1 Tạo sử dụng LINQ. Không phải rất giỏi ... :) – sehe

3

gì về cách tiếp cận biểu hiện thường xuyên thanh lịch này:

Regex.Replace("[Hello World]", @"[\[\]]", "[$0]"); 

Đơn vị kiểm tra nó?

[TestMethod] 
public void UnitTestThat() 
{ 
    Assert.AreEqual(@"[[]Hello World[]]", Regex.Replace("[Hello World]", @"[\[\]]", "[$0]")); 
} 

thử nghiệm thông qua


Sửa @JohnMcGrant

Đây là một phiên bản hơi ít hiệu quả của mã của bạn, trong đó có, bằng cách này, chính xác hành vi tương tự như các regex trên:

string result = input.Aggregate(new StringBuilder(), (a, c) => 
    -1 != "[]".IndexOf(c) ? a.AppendFormat("[{0}]", c) : a.Append(c)).ToString(); 
+0

Có thể an toàn để giả định điều này sẽ không xảy ra, nhưng nếu văn bản được gắn khung hợp pháp có thể chứa dấu ngoặc, có thể bị thoát theo một cách nào đó. Nó sẽ không phá vỡ regex? –

+0

@JohnMGant: Không, bởi vì điều đó có nghĩa là các yêu cầu đã thay đổi. Điều gì sẽ xảy ra nếu câu hỏi khác? Điều đó có phá vỡ câu trả lời không? Không. – sehe

+0

Đã thêm phương pháp thay thế dựa trên phiên bản của @ JohnMGant. Tôi nghĩ rằng regex vẫn là cách tiếp cận tốt nhất :) – sehe

1
StringBuilder result = new StringBuilder(); 

    foreach (Char singleCharacter in str) 
    { 
     result.Append(singleCharacter.Equals('[') ? "[[]" : singleCharacter.Equals(']') ? "[]]" : singleCharacter.ToString()); 
    } 

    str = result.ToString(); 
0

Tôi có cùng một vấn đề chính xác, vì vậy tôi đã thực hiện một chức năng trợ giúp để thực hiện điều đó

protected string ReplaceUsingDictionary(string subject, Dictionary<string,string> pairs) 
    { 
     StringBuilder sb = new StringBuilder(subject); 

     sb.Replace("{", "{{").Replace("}", "}}"); 

     int i=0; 
     foreach (string key in pairs.Keys.ToArray()) 
     { 
      sb.Replace(
       key.Replace("{", "{{").Replace("}", "}}"), 
       "{" + i + "}" 
      ); 

      i++; 
     } 

     return string.Format(sb.ToString(), pairs.Values.ToArray()); 
    } 

// usage 
Dictionary<string, string> replacements = new Dictionary<string, string>(); 
replacements["["] = "[[]"; 
replacements["]"] = "[]]"; 

string mystr = ReplaceWithDictionary("[HelloWorld]", replacements); // returns [[]HelloWorld[]] 
Các vấn đề liên quan