2012-05-26 40 views
5

Tôi đang cố cắt một chuỗi thành lần xuất hiện đầu tiên của một từ cụ thể trong một chuỗi các từ được phân tách bằng dấu phẩy. Ví dụ .:Xóa lần xuất hiện cuối cùng trong chuỗi

deleteLastOccurrence("foo,bar,dog,cat,dog,bird","dog") 

nên trở

"foo,bar,dog" 

Tôi có những điều sau đây, và nó dường như không được làm việc một cách chính xác:

public String deleteLastOccurrence(String original, String target){ 
    String[] arr = original.split(","); 
    arr = Arrays.copyOfRange(arr, Arrays.asList(arr).indexOf(target), original.length()-1); 
    path = StringUtils.join(pathArray,","); 
} 

Bất kỳ đề xuất về một phương pháp đơn giản hơn? Cảm ơn trước ...

+0

là gì 'đường dẫn'? Phương thức _not_ của bạn hoạt động như thế nào? (Đầu ra cho đầu vào bạn cung cấp cái gì?) – sarnold

+0

Tôi đang gặp khó khăn khi hiểu phương pháp này được cho là phải làm gì. Nó có xóa mọi thứ sau lần đầu tiên của đối số thứ hai không? Nếu tôi đọc ví dụ của bạn sử dụng "deleteLastOccurrance" trong mã của ai đó, tôi chắc chắn sẽ không * mong đợi nó trả về "foo, bar, dog". Thay vào đó, tôi sẽ mong đợi "foo, bar, dog, cat, bird". –

+0

Sử dụng kết hợp String.indexOf và String.substring sẽ là đủ. – dragon66

Trả lời

7

Sử dụng regex thay thế:

public static String deleteLastOccurrence(String original, String target){ 
    return original.replaceAll("(,)?\\b" + target + "\\b.*", "$1" + target); 
} 

Mã này cũng hoạt động khi mục tiêu là từ đầu tiên hoặc cuối cùng trong bản gốc (do đó cú pháp regex \b có nghĩa là "ranh giới từ")

Ngoài ra, đổi tên phương thức thành deleteAfterFirstOccurrence(), vì tên hiện tại của bạn gây hiểu lầm: "lần xuất hiện cuối cùng" không liên quan đến những gì bạn muốn.

Dưới đây là một thử nghiệm nhỏ:

public static void main(String[] args) { 
    // Test for target in middle: 
    System.out.println(deleteLastOccurrence("foo,bar,dog,cat,dog,bird,dog", "dog")); 
    // Test for target at start: 
    System.out.println(deleteLastOccurrence("dog,bar,dog,cat,dog,bird,dog", "dog")); 
    // Test for target at end: 
    System.out.println(deleteLastOccurrence("foo,bar,cat,bird,dog", "dog")); 
} 

Output:

foo,bar,dog 
dog 
foo,bar,cat,bird,dog 
+0

Sẽ không loại bỏ tất cả các lần xuất hiện? Không chỉ là cuối cùng? (Java của tôi là một chút gỉ) – Wolph

+0

@WoLpH Điều này sẽ cắt rất nhiều, bởi vì có một '. *' ở cuối. – Bohemian

+0

Khá bóng bẩy. Một câu hỏi ... bạn không kết thúc tước bỏ một dấu phẩy khi trận đấu của bạn là ở giữa và khi bạn làm thay thế nó không được đưa trở lại? – christurnerio

0

Làm thế nào về điều này:

public String deleteLastOccurrence(String original, String target){ 
    return original.replace("(^|,)" + target + "(,|$)", ""); 
} 
+0

Tôi tin rằng điều này sẽ thay thế tất cả chúng, phải không? Hoặc ít nhất không phải là cuối cùng. – coreyhaines

+0

@coreyhaines: Tôi hy vọng 'thay thế' để thay thế và' replaceAll' để thay thế tất cả chúng thực sự :) – Wolph

0

Dưới đây là một thử tại một phiên bản không-regex:

public String trimTo(String in, String matchNoCommas) { 
    if (in.startsWith(matchNoCommas + ",")) // special check here... 
     return matchNoCommas; 
    int idx = in.indexOf("," + matchNoCommas+ ","); 
    if (idx < 0) 
     return in; 
    return in.substring(0, idx + matchNoCommas.length()+1); 
} 

Cung cấp kết quả tương tự như phiên bản regex của @Bohemian. Cuộc gọi của bạn càng dễ hiểu.

2

CẬP NHẬT: Đã xem xét kỹ hơn câu hỏi và nhận ra rằng tôi đã viết tên của phương thức chứ không phải kết quả mà OP muốn. Vì vậy, nó chỉ được thoát khỏi sự xuất hiện cuối cùng, không cắt sau nó. Oh well! :)

Tùy thuộc vào phong cách của bạn, bạn có thể không nghĩ rằng điều này đơn giản hơn. Nhưng, đó là một vấn đề thú vị. Tôi nghĩ rằng mã này rõ ràng hơn một chút.

public class ReplaceLast { 

public String deleteLastOccurrence(String fromThis, String word){ 
    int wordLength = word.length(); 
    if(fromThis.startsWith(word + ",")){ 
     return fromThis.substring(wordLength + 1); 
    } 
    if(fromThis.endsWith("," + word)){ 
     return fromThis.substring(0, fromThis.length() - wordLength - 1); 
    } 
    int index = fromThis.lastIndexOf("," + word + ","); 
    if(index == -1){ 
     return fromThis; 
    } 
    return fromThis.substring(0, index) + fromThis.substring(index+word.length() + 1); 
} 
@Test 
public void testNotThere() { 
    String actual = deleteLastOccurrence("foo,bar,dog,cat,dog,bird","moose"); 
    assertEquals("foo,bar,dog,cat,dog,bird", actual); 
} 
@Test 
public void testMiddle() { 
    String actual = deleteLastOccurrence("foo,bar,dog,cat,dog,bird","dog"); 
    assertEquals("foo,bar,dog,cat,bird", actual); 
} 

@Test 
public void testFirst() { 
    String actual = deleteLastOccurrence("foo,bar,dog,cat,dog,bird","foo"); 
    assertEquals("bar,dog,cat,dog,bird", actual); 
} 

@Test 
public void testLast() { 
    String actual = deleteLastOccurrence("foo,bar,dog,cat,dog,bird","bird"); 
    assertEquals("foo,bar,dog,cat,dog", actual); 
} 

@Test 
public void testSubword() { 
    String actual = deleteLastOccurrence("foo,bar,dog,cat,dog,bird","bir"); 
    assertEquals("foo,bar,dog,cat,dog,bird", actual); 
} 
} 
+0

Tôi tin rằng mã này sẽ cắt Chuỗi nếu từ đó là "do" (không phải là "con chó"). , Tôi * nghĩ *, hành vi không chính xác. (Mặc dù OP là một chút không rõ ràng - đây là nơi bạn quay trở lại và kiểm tra các yêu cầu. :-) – user949300

+0

Doh! Bạn đúng rồi. :) Cần phải là một từ đầy đủ phù hợp. – coreyhaines

+0

Đã chỉnh sửa! Nên làm việc ngay bây giờ. – coreyhaines

0

Có thể tôi đã sai, nhưng điều này có đúng không?

public trimCommaSeparatedListToIncludeFirstOccurrenceOfWord(String listOfWords, String wordToMatch) { 
    int startOfFirstOccurrenceOfWordToMatch = listOfWords.indexOf(wordToMatch); 
    int endOfFirstOccurrenceOfWordToMatch = startOfFirstOccurrenceOfWordToMatch + wordToMatch.length() - 1; 

    return listOfWords.substring(0, endOfFirstOccurrenceOfWordToMatch); 
} 

Bây giờ điều này có thể không phải là những gì OP muốn, nhưng tôi nghĩ đó là những gì OP yêu cầu. Ví dụ: f("doggy,cat,bird", "dog") sẽ trả về "dog".

Để đối sánh toàn bộ từ, tôi muốn đánh giá lại kẻ hút như những người khác đã đề xuất.

+0

Tôi thấy quan điểm đơn giản của bạn nhưng bạn ít nhất cũng nên kiểm tra trường hợp của từ không có mặt để tránh phản hồi không chính xác. Một cái gì đó như "if (! ListOfWords.contains (wordToMatch)) trả về listOfWords;" – gicappa

+0

Tôi nghĩ rằng trong ví dụ của bạn OP sẽ mã trở lại "chó, mèo, chim", "chó". Anh ta muốn tìm kiếm toàn bộ các từ xuất hiện. –

+0

Ah yes, @gicappa: mỗi khi tôi không viết bài kiểm tra, tôi nhớ một trường hợp biên đơn giản. –

1

Tôi đã cố gắng giải quyết vấn đề cắt xén chuỗi khi xuất hiện lần đầu tiên của một từ cụ thể và tôi không quan tâm đến tên gốc của phương thức (deleteLastOccurrence) là IMO gây hiểu nhầm.

Bí quyết chỉ đối sánh một từ và không phải từ con cho tôi là thêm hai dấu phẩy trước và sau câu rồi kiểm tra từ bằng dấu phẩy.

tức là ",dog," sẽ được kiểm tra với số ",foo,bar,dog,cat,dog,bird," để hiện diện.

package gicappa; 

public class So { 
    public static String trimSentenceOnFirstOccurrenceOf(String sentence, String word) { 
     if (word.isEmpty()) return sentence; 

     if (!addCommasAround(sentence).contains(addCommasAround(word))) return sentence; 

     return trimAddedCommasOf(substringOfSentenceUntilEndOfWord(addCommasAround(sentence), addCommasAround(word))); 
    } 

    public static String substringOfSentenceUntilEndOfWord(String string, String word) { 
     return string.substring(0, string.indexOf(word) + word.length()); 
    } 

    public static String trimAddedCommasOf(String string) {return string.substring(1,string.length()-1);} 

    public static String addCommasAround(String s) {return "," + s + ","; } 
} 

và nếu bạn muốn ưa thích một số thử nghiệm tôi đã sử dụng cho TDD, ở đây chúng tôi đi:

package gicappa; 

import org.junit.Test; 

import static gicappa.So.trimSentenceOnFirstOccurrenceOf; 
import static org.hamcrest.core.Is.is; 
import static org.hamcrest.core.IsEqual.equalTo; 
import static org.junit.Assert.assertThat; 

public class SoTest { 
    @Test 
    public void it_returns_the_same_sentence_for_empty_word() { 
     assertThat(trimSentenceOnFirstOccurrenceOf("foo,bar,dog,cat,dog,bird", ""), is(equalTo("foo,bar,dog,cat,dog,bird"))); 
    } 

    @Test 
    public void it_returns_the_same_sentence_for_not_contained_word() { 
     assertThat(trimSentenceOnFirstOccurrenceOf("foo,bar,dog,cat,dog,bird", "s"), is(equalTo("foo,bar,dog,cat,dog,bird"))); 
    } 

    @Test 
    public void it_returns_the_first_word() { 
     assertThat(trimSentenceOnFirstOccurrenceOf("foo,bar,dog,cat,dog,bird", "foo"), is(equalTo("foo"))); 
    } 

    @Test 
    public void it_returns_the_same_sentence_if_is_matched_the_last_word() { 
     assertThat(trimSentenceOnFirstOccurrenceOf("foo,bar,dog,cat,dog,bird", "bird"), is(equalTo("foo,bar,dog,cat,dog,bird"))); 
    } 

    @Test 
    public void it_trims_after_the_end_of_the_first_matched_word() { 
     assertThat(trimSentenceOnFirstOccurrenceOf("foo,bar,dog,cat,dog,bird", "dog"), is(equalTo("foo,bar,dog"))); 
    } 

    @Test 
    public void it_does_not_trim_for_a_subword_of_a_contained_word() { 
     assertThat(trimSentenceOnFirstOccurrenceOf("foo,bar,dog,cat,dog,bird", "do"), is(equalTo("foo,bar,dog,cat,dog,bird"))); 
    } 

    @Test 
    public void it_does_not_trim_for_a_subword_of_an_already_contained_word() { 
     assertThat(trimSentenceOnFirstOccurrenceOf("dog,foozzo,foo,cat,dog,bird", "foo"), is(equalTo("dog,foozzo,foo"))); 
    } 
} 

Một refactoring dài dòng cho một lớp OO hơn cũng có thể là:

package gicappa; 

public class Sentence { 
    private String s; 

    public Sentence(String sentence) { 
     this.s = sentence; 
    } 

    public String trimOnFirstOccurrenceOf(String word) { 
     if (word.isEmpty() || csvSentenceContainsWord(word)) return s; 

     return substringSentenceToEndOf(word); 
    } 

    private String substringSentenceToEndOf(String word) { 
     return addCommasTo(s).substring(1, addCommasTo(s).indexOf(addCommasTo(word)) + addCommasTo(word).length()-1); 
    } 

    private boolean csvSentenceContainsWord(String word) { 
     return !addCommasTo(s).contains(addCommasTo(word)); 
    } 

    public static String addCommasTo(String s) {return "," + s + ",";} 
} 

với cách sử dụng như:

new Sentence("dog,foozzo,foo,cat,dog,bird").trimOnFirstOccurrenceOf("foo"), is(equalTo("dog,foozzo,foo")) 
+1

Tôi nghĩ bạn phải trả lời câu.chuỗi con (0, câu.indexOf (addCommasTo (word)) + word.length()); hoặc bạn sẽ so khớp, ví dụ: foo trong "chó, foozzo, foo, mèo, chó, chim" với "chó, foo", thay vào đó bạn phải trả lại chó, foozzo, foo –

+0

yups bạn nói đúng nhưng tôi phải mò mẫm nó nhiều hơn thế. Cảm ơn – gicappa

0

gonzoc0din g, sau khi đọc tất cả các câu trả lời, IMHO cách bạn làm điều đó là đơn giản hơn và sạch hơn, ngoại trừ việc cần được sửa chữa theo cách này:

public String deleteLastOccurrence(String original, String target){ 
    String[] arr = original.split(","); 
    arr = Arrays.copyOfRange(arr,0, Arrays.asList(arr).indexOf(target)); 
    path = StringUtils.join(arr,","); 
} 

Nhưng có lẽ tôi đã không hiểu yêu cầu của bạn ...

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