1

I want to get the string between 2 words in a string. like so:

String s = "Play A ROCK song"

So I want to get the string between: A and song, which in this case is rock.

I tried this:

    public static String subStringBetween(String text, String after, String before) {
    String p1 = getWordsAfter(text, after);
    String p2 = getWordsBefore(text, before);

    Set<String> aSet = new HashSet<>(Arrays.asList(p1.split(" ")));
    Set<String> bSet = new HashSet<>(Arrays.asList(p2.split(" ")));

    Set<String> result = new HashSet<>(aSet);
    result.retainAll( bSet);
    String string = "";
    for (String s : result) {
        if (string == "") {
            string = s;
        }else{
            string +=" " + s;
        }
    }
    return string;
}

public static String getWordsAfter(String text, String word) {
    String[] splt = text.split(word);
    return splt[1];
}

public static String getWordsBefore(String text, String word) {
    String[] splt = text.split(word);
    return splt[0];
}

It works, but If the string between A and Song is more than one word, it works, but prints something weird, like if it was: Play a Nice Rock Song the return would be Rock Nice, not Nice Rock

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Liwaa
  • 35
  • 9

2 Answers2

2

This is a very novel way of going about this, so I'll respect that and not suggest regular expressions (although that would be the more straightforward approach).

In this context, you've run into an issue: hash sets are not guaranteed to be in any specific order, and since you're iterating over them in a specific order, who knows what order those strings will come in?

The fix is actually very simple. Make use of the LinkedHashSet class instead. This is guaranteed to preserve insertion order.

Do this for all of the sets you're using.

Set<String> aSet = new LinkedHashSet<>(Arrays.asList(p1.split(" ")));
Set<String> bSet = new LinkedHashSet<>(Arrays.asList(p2.split(" ")));

Set<String> result = new LinkedHashSet<>(aSet);

Then, the order will be what you expect when you invoke your method.

Makoto
  • 104,088
  • 27
  • 192
  • 230
  • this gave an empty string :/ – Liwaa Jan 11 '17 at 20:15
  • @Liwaa: In every example I ran it performed fine. Without specific inputs it'll be impossible to tell you what caused that. – Makoto Jan 11 '17 at 20:21
  • input: play a rock song output: Playing a Song – Liwaa Jan 11 '17 at 20:39
  • @Liwaa: The likely issue there is one of casing. In your `getWordsAfter` and `getWordsBefore` methods, you don't take whitespace into account; that is, you're not treating `word` as an actual "word". That's *slightly* tricker to deal with, but it involves you making a decision around how `word` should be treated - do you treat it as a word with guaranteed whitespace around it or not? It worked fine with mixed-case settings, which is what led me to this conclusion. – Makoto Jan 11 '17 at 20:42
1

You can also try a little bit shorter code:

public static String subStringBetween(String text, String after, String before) {
    Pattern pattern = Pattern.compile("(?<=\\s|^)"+after +"\\s(.*?)\\s+"+ before);
    Matcher matcher = pattern.matcher(text);

    while (matcher.find()) {
        return matcher.group(1);
    }
    return ""; //or null or whatever you need

}

Input: Play a Nice Rock Song 
After: a 
Before: Song
Output: Nice Rock

Input: play a rock song xxx
After: a 
Before: song
Output: rock

Input: a Play Nice Rock Song
After: a 
Before: Song
Output: Play Nice Rock

Input: aaaa bbbb a bbb aaa b aaaa bbb
After: a 
Before: b
Output: bbb aaa
Planck Constant
  • 1,406
  • 1
  • 17
  • 19