5

我正在尝试将字符串修剪为单个逗号分隔单词字符串中特定单词的第一次出现。例如:

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

应该返回

"foo,bar,dog"

我有以下内容,但它似乎无法正常工作:

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,",");
}

对更简单的方法有什么建议吗?提前致谢...

4

7 回答 7

7

Use regex replace:

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

This code also works when the target is the first or last word in the original (hence the regex syntax \b which means "word boundary")

Also, rename your method to deleteAfterFirstOccurrence(), because your current name is misleading: The "last occurrence" is irrelevant to what you want.

Here's a little test:

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
于 2012-05-26T00:59:49.237 回答
2

更新:仔细查看问题并意识到我写了方法的名称,而不是 OP 想要的结果。所以,它只是摆脱了最后一次出现,而不是在它之后修剪。那好吧!:)

根据您的风格,您可能认为这并不简单。但是,这是一个有趣的问题。我认为这段代码更清晰一些。

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);
}
}
于 2012-05-26T01:19:35.480 回答
1

我试图解决在特定单词第一次出现时修剪字符串的问题,我并不关心deleteLastOccurrenceIMO 误导的方法的原始名称 ()。

对我来说,只匹配单个单词而不匹配子词的技巧是在句子前后添加两个逗号,然后用逗号检查单词。

即将 ",dog,"检查",foo,bar,dog,cat,dog,bird,"是否存在。

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 + ","; }
}

如果你喜欢我用于 TDD 的一些测试,我们开始吧:

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")));
    }
}

对更多 OO 类的冗长重构也可能是:

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 + ",";}
}

用法如下:

new Sentence("dog,foozzo,foo,cat,dog,bird").trimOnFirstOccurrenceOf("foo"), is(equalTo("dog,foozzo,foo"))
于 2012-05-26T20:06:55.120 回答
0

这是非正则表达式版本的尝试:

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);
}

提供与@Bohemian 的正则表达式版本相同的结果。你的电话哪个更容易理解。

于 2012-05-26T01:18:00.583 回答
0

也许我错了,但这不是吗?

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

    return listOfWords.substring(0, endOfFirstOccurrenceOfWordToMatch);
}

现在这可能不是 OP 想要的,但我认为这是 OP 所要求的。示例:f("doggy,cat,bird", "dog")将返回"dog".

对于全字匹配,我会像其他人建议的那样对吸盘进行正则表达式。

于 2012-05-26T16:52:20.690 回答
0

How about this:

public String deleteLastOccurrence(String original, String target){
    return original.replace("(^|,)" + target + "(,|$)", "");
}
于 2012-05-26T01:01:00.273 回答
0

gonzoc0ding,在阅读了所有回复后,恕我直言,您的做法更简单、更干净,但应以这种方式更正:

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,",");
}

但也许我没有理解你的要求......

于 2012-05-26T20:28:29.960 回答