8

I am going through the Java CodingBat exercises. Here is the one I have just completed:

Given a string and a non-empty word string, return a string made of each char just before and just after every appearance of the word in the string. Ignore cases where there is no char before or after the word, and a char may be included twice if it is between two words.

My code, which works:

public String wordEnds(String str, String word){

    String s = "";
    String n = " " + str + " "; //To avoid OOB exceptions

    int sL = str.length();
    int wL = word.length();
    int nL = n.length();

    int i = 1;

    while (i < nL - 1) {

        if (n.substring(i, i + wL).equals(word)) {
            s += n.charAt(i - 1);
            s += n.charAt(i + wL);
            i += wL;
        } else {
            i++;
        }
    }

    s = s.replaceAll("\\s", "");

    return s;
}

My question is about regular expressions. I want to know if the above is doable with a regex statement, and if so, how?

4
  • This problem may be difficult to solve with Java regular expressions, because the matches may overlap, e.g. abcXY1XYijk matching on XY would have cXY1 and 1XYi as groups. Commented Apr 9, 2015 at 2:57
  • Great question, by the way ^ ^ Commented Apr 9, 2015 at 2:59
  • add some input and expected output Commented Apr 9, 2015 at 4:18
  • 1
    UTF-16 is variable width, not fixed width. Each character takes up one or two code units. So chatAt is wrong. Commented Apr 12, 2015 at 0:28

3 Answers 3

3

You can use Java regex objects Pattern and Matcher for doing this.

public class CharBeforeAndAfterSubstring {
    public static String wordEnds(String str, String word) {
        java.util.regex.Pattern p = java.util.regex.Pattern.compile(word);
        java.util.regex.Matcher m = p.matcher(str);
        StringBuilder beforeAfter = new StringBuilder();

        for (int startIndex = 0; m.find(startIndex); startIndex = m.start() + 1) {
            if (m.start() - 1 > -1)
                beforeAfter.append(Character.toChars(str.codePointAt(m.start() - 1)));
            if (m.end() < str.length())
                beforeAfter.append(Character.toChars(str.codePointAt(m.end())));
        }

        return beforeAfter.toString();
    } 
    public static void main(String[] args) {
        String x = "abcXY1XYijk";
        String y = "XY";
        System.out.println(wordEnds(x, y));

    }
} 
Sign up to request clarification or add additional context in comments.

4 Comments

I appreciate the 'may be' part o the question is ambiguous. In this case, it should be included, or the test is failed
@alanbuchanan Edited the answer, please check out. A little more indexing logic is added to make sure overlaps are accounted properly.
That won’t work right with 16/17 planes of 😱Unicode😱. Please stop using charAt: it is not fit for purpose.
Thanks @tchrist. Made amends. This was a beginner question, so didn't bother much about unicode.
1
(?=(.|^)XY(.|$))

Try this.Just grab the captures and remove the None or empty values.See demo.

https://regex101.com/r/sJ9gM7/73

1 Comment

This doesn't take into account the fact that XY might be something else, as defined by str in the question
1

To get a string containing the character before and after each occurrence of one string within the other, you could use the regex expression:

"(^|.)" + str + "(.|$)"

and then you could iterate through the groups and concatenate them.

This expression will look for (^|.), either the start of the string ^ or any character ., followed by str value, followed by (.|$), any character . or the end of the string $.

You could try something like this:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public String wordEnds(String str, String word){
    Pattern p = Pattern.compile("(.)" + str + "(.)");
    Matcher m = p.matcher(word);
    String result = "";
    int i = 0;
    while(m.find()) {
        result += m.group(i++);
    }
    return result;
}

4 Comments

how does it do return a string made of each char just before and just after every appearance of the word in the string ?
@Scary Wombat Thanks for the feedback. You are right. I was replacing instead of returning just those characters, the opposite of what was asked. Updated the answer.
Your code is failing most of the tests at codingbat.com/prob/p147538 from which the OP is trying to learn from.
@user883499 Updated logic in expression.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.