2012-11-03 31 views
5

Tôi hiện đang cố gắng giải quyết vấn đề từ codingbat.com với các cụm từ thông dụng.Lặp lại qua String với .find() trong Java regex

Tôi mới làm điều này, vì vậy các giải thích từng bước sẽ được đánh giá cao. Tôi có thể giải quyết điều này với các phương thức String tương đối dễ dàng, nhưng tôi đang cố gắng sử dụng các biểu thức chính quy.

Đây là lời nhắc: Cho một chuỗi và một chuỗi từ không trống, trả về một chuỗi được tạo từ mỗi char ngay trước và sau mỗi lần xuất hiện của từ trong chuỗi. Bỏ qua các trường hợp không có char trước hoặc sau từ, và một char có thể được bao gồm hai lần nếu nó nằm giữa hai từ.

wordEnds("abcXY123XYijk", "XY") → "c13i" 
wordEnds("XY123XY", "XY") → "13" 
wordEnds("XY1XY", "XY") → "11" 

vv

Mã của tôi vậy, đến nay:

String regex = ".?" + word+ ".?"; 
Pattern p = Pattern.compile(regex); 
Matcher m = p.matcher(str); 

String newStr = ""; 
while(m.find()) 
    newStr += m.group().replace(word, ""); 

return newStr; 

Vấn đề là khi có nhiều trường hợp của chữ trong một hàng, các chương trình bỏ lỡ nhân vật trước từ vì m. find() tiến xa hơn nó.

Ví dụ: wordEnds("abc1xyz1i1j", "1") nên trở "cxziij", nhưng phương pháp của tôi trả "cxzij", không lặp lại những "i"

tôi sẽ đánh giá cao một giải pháp không lộn xộn với một lời giải thích tôi có thể áp dụng đối với các vấn đề regex chung khác.

+0

Xem câu trả lời này về các biểu thức nhìn xung quanh thường xuyên http: // stackoverflow. com/a/2995621/324900 – Reddy

+0

thực sự hữu ích, cảm ơn – Rishi

+0

rất vui khi được trợ giúp! :) – Reddy

Trả lời

1

Đây là một giải pháp một liner:

String wordEnds = input.replaceAll(".*?(.)" + word + "(?:(?=(.)" + word + ")|(.).*?(?=$|." + word + "))", "$1$2$3"); 

này phù hợp với trường hợp cạnh bạn như một cái nhìn về phía trước trong một nhóm không chụp, sau đó phù hợp với thông thường (tiêu thụ) trường hợp.

Lưu ý rằng các yêu cầu của bạn không yêu cầu lặp lại, chỉ tiêu đề câu hỏi của bạn giả định nó là cần thiết, mà nó không phải là. Ngoài ra, nếu bạn không thể đảm bảo điều đó, bạn cần sử dụng Pattern.quote(word) thay vì word.

Dưới đây là một bài kiểm tra của vụ án thông thường và các trường hợp cạnh, cho thấy nó hoạt động:

public static String wordEnds(String input, String word) { 
    word = Pattern.quote(word); // add this line to be 100% safe 
    return input.replaceAll(".*?(.)" + word + "(?:(?=(.)" + word + ")|(.).*?(?=$|." + word + "))", "$1$2$3"); 
} 

public static void main(String[] args) { 
    System.out.println(wordEnds("abcXY123XYijk", "XY")); 
    System.out.println(wordEnds("abc1xyz1i1j", "1")); 
} 

Output:

c13i 
cxziij 
+0

Điều này không hoàn toàn đúng - tôi sẽ quay lại sau này – Bohemian

+0

bây giờ tôi có được hiệu quả như thế nào, nhờ – Rishi

+0

@Bohemian đó là không chính xác ông cần 'cxziij' như đầu ra không' cxzi' .. đó là lý do yi đã sử dụng lookarounds ... – Anirudha

0

Sử dụng lookbehind tích cực và lookahead postive đó là khẳng định zero-width

(?<=(.)|^)1(?=(.)|$) 
    ^ ^ ^-looks for a character after 1 and captures it in group2 
    |  |->matches 1..you can replace it with any word 
    | 
    |->looks for a character just before 1 and captures it in group 1..this is zero width assertion that doesn't move forward to match.it is just a test and thus allow us to capture the values 

$1$2 chứa value..Go của bạn vào việc tìm kiếm cho đến khi kết thúc

Vì vậy, đây nên được như thế

String s1 = "abcXY123XYiXYjk"; 
String s2 = java.util.regex.Pattern.quote("XY"); 
String s3 = ""; 
String r = "(?<=(.)|^)"+s2+"(?=(.)|$)"; 
Pattern p = Pattern.compile(r); 
Matcher m = p.matcher(s1); 
while(m.find()) s3 += m.group(1)+m.group(2); 
//s3 now contains c13iij 

hoạt động here

+0

cảm ơn! có lẽ nên đọc thêm ... – Rishi

+4

-1 Waaaaaay quá phức tạp, và thực sự sai. Bạn không cần nhìn xung quanh! Chỉ cần sử dụng '(.)' - anh ta nói "không phù hợp nếu không có một nhân vật", nhưng bạn đang đạt được bằng cách kết hợp bắt đầu và kết thúc, đó là thực sự * không * những gì OP nói rằng ông muốn – Bohemian

+0

@ Bohemian Tôi thích câu trả lời ban đầu của bạn vì sự đơn giản của nó, vì vậy tôi sẽ đánh giá cao nếu bạn có thể đăng bài đó (với str.replace) – Rishi

0

Sử dụng regex như sau:

Matcher m = Pattern.compile("(.|)" + Pattern.quote(b) + "(?=(.?))").matcher(a); 
for (int i = 1; m.find(); c += m.group(1) + m.group(2), i++); 

Kiểm tra this demo.

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