Java 删除字符串中的最后一个匹配项

Java 删除字符串中的最后一个匹配项,java,string,Java,String,我正在尝试将一个字符串修剪为逗号分隔的单个字符串中特定单词的第一次出现。例如: deleteLastOccurrence("foo,bar,dog,cat,dog,bird","dog") 应该回来 "foo,bar,dog" 我有以下几点,但它似乎工作不正常: public String deleteLastOccurrence(String original, String target){ String[] arr = original.split(","); arr

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

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,",");
}
对更简单的方法有什么建议吗?提前感谢…

使用正则表达式替换:

public static String deleteLastOccurrence(String original, String target){
    return original.replaceAll("(,)?\\b" + target + "\\b.*", "$1" + target);
}
当目标是原文中的第一个或最后一个单词时,此代码也起作用(因此regex语法
\b
表示“单词边界”)

另外,将方法重命名为
deleteAfterFirstOccurrence()
,因为您当前的名称具有误导性:“最后一次出现”与您想要的内容无关

这里有一个小测试:

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

foo,bar,dog
dog
foo,bar,cat,bird,dog
这个怎么样:

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

下面是一个非正则表达式版本的尝试:

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);
}
public String trimTo(String-in,String-matchNoCommas){
if(in.startsWith(matchNoCommas+“,”)//此处特别检查。。。
返回matchNoCommas;
int idx=in.indexOf(“,”+matchNoCommas+“,”);
if(idx<0)
返回;
返回.substring(0,idx+matchNoCommas.length()+1);
}

提供与@Bohemian的正则表达式版本相同的结果。您对哪个方法的调用更容易理解。

更新:仔细查看问题,发现我写的是方法的名称,而不是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);
}
}

也许我错了,但这不是吗

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(“狗、猫、鸟、狗”)
将返回
“狗”


对于完整的单词匹配,我会按照其他人的建议对吸盘进行正则化。

我试图解决在特定单词第一次出现时修剪字符串的问题,但我不在乎方法的原始名称(
deleteLastOccurrence

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

i、 e.
”,狗,
将对照
”,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")));
    }
}
对于一个更加面向对象的类,冗长的重构也可以是:

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

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


但也许我还不了解您的要求…

什么是路径?你的方法怎么不起作用?(它为您提供的输入提供了什么输出?)我很难理解这个方法应该做什么。它会删除第二个参数第一个实例之后的所有内容吗?如果我读了你在某人代码中使用“deletelastcurrence”的例子,我绝对不会期望它返回“foo,bar,dog”。相反,我希望使用“foo、bar、dog、cat、bird”。使用String.indexOf和String.substring的组合就足够了。这难道不会消除所有发生的情况吗?不只是最后一个?(我的Java有点生锈)@WoLpH这会减少很多,因为最后有一个
*
。非常光滑。一个问题。。。当你的匹配在中间时,当你做替换时,你不会把逗号删去吗?当它被放回原处的时候,很好,在我发布之后,我看到了新的修正了这个问题的编辑。波希米亚人:哇,真是个大转变。那不是我说的版本。看起来您的函数是正确的,
deleteLastOccurance
名称似乎是错误的:)我相信如果单词是“do”(而不是“dog”),这段代码将修剪字符串,我认为这是不正确的行为。(虽然OP有点不清楚-这里是你回去检查需求的地方。:-)发现@coreyhaines正在练习java是无价的:)我相信这会取代所有的,不是吗?或者至少不是最后一个。@coreyhaines:我希望
replace
来替换一个,而
replaceAll
来替换所有的:)我明白你的简单性,但你至少应该检查单词not present的大小写,以避免错误的回答。类似于“if(!listOfWords.contains(wordToMatch))return listOfWords”之类的内容;我认为在您的示例中,OP将调用返回“doggy、cat、bird”、“dog”的代码。他开始搜索整个单词的出现情况。啊,是的,@gicappa:每次我不写测试,我都会错过一个简单的边界情况。我想你必须返回句子。子字符串(0,句子。索引of(addCommasTo(word))+word.length();或者你将“狗,福,福,猫,狗,鸟”中的“福”与“狗,福”相匹配,而你必须返回“狗,福,福”你是对的,但我还得再摸索一下。谢谢