2011-09-23 61 views
5

Giả sử bạn có chuỗi sau:Thay thế nhiều chuỗi con trong Java khi văn bản thay thế chồng chéo văn bản tìm kiếm

cat dog fish dog fish cat 

Bạn muốn thay thế tất cả cats với dogs, tất cả dogs với fish, và tất cả fish với cats. Bằng trực giác, kết quả mong đợi:

dog fish cat fish cat dog 

Nếu bạn cố gắng giải pháp rõ ràng, Looping qua với replaceAll(), bạn nhận được:

  1. (bản gốc) cat dog fish dog fish cat
  2. (cat -> chó) dog dog fish dog fish dog
  3. (chó -> cá) fish fish fish fish fish fish
  4. (cá -> mèo) cat cat cat cat cat cat

Rõ ràng, đây không phải là kết quả mong muốn. Vậy cách đơn giản nhất để làm điều này là gì? Tôi có thể cobble một cái gì đó cùng với PatternMatcher (và rất nhiều Pattern.quote()Matcher.quoteReplacement()), nhưng tôi từ chối không tin rằng tôi là người đầu tiên có vấn đề này và không có chức năng thư viện để giải quyết nó.

(FWIW, các trường hợp thực tế là một chút phức tạp hơn và không liên quan đến giao dịch hoán đổi thẳng.)

Trả lời

8

Dường StringUtils.replaceEach trong commons apache làm những gì bạn muốn:

StringUtils.replaceEach("abcdeab", new String[]{"ab", "cd"}, new String[]{"cd", "ab"}); 
// returns "cdabecd" 

Lưu ý rằng documenent tại các liên kết ở trên có vẻ là do lỗi. Xem nhận xét bên dưới để biết chi tiết.

+0

Điều này dường như bị cấm rõ ràng, ít nhất là trong StringUtils 2.5 trở về trước: "Ném: IllegalArgumentException - nếu tìm kiếm lặp lại và có vòng lặp vô tận do đầu ra của đầu vào là đầu vào khác". (Mặc dù những gì tôi thực sự nhận được là một IllegalStateException như đệ quy không ngăn chặn đúng cách.) –

+0

Tôi bối rối. Phương pháp tôi trích dẫn ở trên (mà tôi đã sao chép trực tiếp từ javadocs trực tuyến) thậm chí không xuất hiện. Không có replaceEach với tham số boolean cuối cùng. Mặt khác 'StringUtils.replaceEach (" abcde ", String mới [] {" ab "," cd "}, chuỗi mới [] {" cd "," ab "})' trả về '" cdabe "' có vẻ như chính xác. Tôi đã kiểm tra điều này trên 2,5 –

+0

Ok, một số rõ ràng. 'replaceEachRepeatedly' ném' IllegalStateException' như bạn đã viết. 'replaceEach' với tham số' boolean' cuối cùng không tồn tại. 'replaceEach' không có tham số' boolean' cuối cùng dường như thực hiện công việc. –

4

tôi sẽ tạo ra một StringBuilder và sau đó phân tích các văn bản lần, một từ cùng một lúc, chuyển qua các từ không thay đổi hoặc thay đổi các từ khi tôi đi. Tôi sẽ không phân tích nó cho mỗi lần trao đổi như bạn đang đề xuất.

Vì vậy, chứ không phải làm một cái gì đó như:

// pseudocode 
text is new text swapping cat with dog 
text is new text swapping dog with fish 
text is new text swapping fish with cat 

Tôi muốn làm

for each word in text 
    if word is cat, swap with dog 
    if word is dog, swap with fish 
    if word is fish, swap with cat 
    transfer new word (or unchanged word) into StringBuilder. 

tôi có lẽ muốn tạo ra một phương pháp (...) hoán đổi cho điều này và sử dụng một HashMap cho trao đổi.

Ví dụ

import java.util.HashMap; 
import java.util.Map; 
import java.util.Scanner; 

public class SwapWords { 
    private static Map<String, String> myMap = new HashMap<String, String>(); 

    public static void main(String[] args) { 
     // this would really be loaded using a file such as a text file or xml 
     // or even a database: 
     myMap.put("cat", "dog"); 
     myMap.put("dog", "fish"); 
     myMap.put("fish", "dog"); 

     String testString = "cat dog fish dog fish cat"; 

     StringBuilder sb = new StringBuilder(); 
     Scanner testScanner = new Scanner(testString); 
     while (testScanner.hasNext()) { 
     String text = testScanner.next(); 
     text = myMap.get(text) == null ? text : myMap.get(text); 
     sb.append(text + " "); 
     } 

     System.out.println(sb.toString().trim()); 
    } 
} 
7
String rep = str.replace("cat","§1§").replace("dog","§2§") 
       .replace("fish","§3§").replace("§1§","dog") 
       .replace("§2§","fish").replace("§3§","cat"); 

Ugly và không hiệu quả như là địa ngục, nhưng công trình.


OK, đây là phiên bản phức tạp và tổng quát hơn. Tôi thích sử dụng biểu thức chính quy hơn là máy quét. Bằng cách đó tôi có thể thay thế các chuỗi tùy ý, không chỉ các từ (có thể tốt hơn hoặc tệ hơn).Dù sao, ở đây đi:

public static String replace(
    final String input, final Map<String, String> replacements) { 

    if (input == null || "".equals(input) || replacements == null 
     || replacements.isEmpty()) { 
     return input; 
    } 
    StringBuilder regexBuilder = new StringBuilder(); 
    Iterator<String> it = replacements.keySet().iterator(); 
    regexBuilder.append(Pattern.quote(it.next())); 
    while (it.hasNext()) { 
     regexBuilder.append('|').append(Pattern.quote(it.next())); 
    } 
    Matcher matcher = Pattern.compile(regexBuilder.toString()).matcher(input); 
    StringBuffer out = new StringBuffer(input.length() + (input.length()/10)); 
    while (matcher.find()) { 
     matcher.appendReplacement(out, replacements.get(matcher.group())); 
    } 
    matcher.appendTail(out); 
    return out.toString(); 
} 

Mã kiểm tra:

System.out.println(replace("cat dog fish dog fish cat", 
    ImmutableMap.of("cat", "dog", "dog", "fish", "fish", "cat"))); 

Output:

chó cá cá mèo mèo chó

Rõ ràng giải pháp này chỉ có ý nghĩa đối với nhiều người thay thế, nếu không nó là một overkill rất lớn.

+0

1 đẹp, tôi thích nó –

+0

@ Eng.Fouad nó không thể thích một sự gớm ghiếc xấu xí như vậy :-) –

+0

Tôi thích ý tưởng để thay thế các từ bằng các từ tạm thời –

0
public class myreplase { 
    public Map<String, String> replase; 

    public myreplase() { 
     replase = new HashMap<String, String>(); 

     replase.put("a", "Apple"); 
     replase.put("b", "Banana"); 
     replase.put("c", "Cantalope"); 
     replase.put("d", "Date"); 
     String word = "a b c d a b c d"; 

     String ss = ""; 
     Iterator<String> i = replase.keySet().iterator(); 
     while (i.hasNext()) { 
      ss += i.next(); 
      if (i.hasNext()) { 
       ss += "|"; 
      } 
     } 

     Pattern pattern = Pattern.compile(ss); 
     StringBuilder buffer = new StringBuilder(); 
     for (int j = 0, k = 1; j < word.length(); j++,k++) { 
      String s = word.substring(j, k); 
      Matcher matcher = pattern.matcher(s); 
      if (matcher.find()) { 
       buffer.append(replase.get(s)); 
      } else { 
       buffer.append(s); 
      } 
     } 
     System.out.println(buffer.toString()); 
    } 

    public static void main(String[] args) { 
     new myreplase(); 
    } 
} 

Output: - của Apple Banana dưa vàng ngày của Apple Banana dưa vàng ngày

Các vấn đề liên quan