# Find two equal substrings in a string

I have various strings that contain codes, e.g. like this:

"file = new JarFile(new File()" + "\nSystem.out.println(file"


but also

"args"


Now I want to find the substring that is in the beginning and in the end of the string. E.g. in the first case the result would be file. In the second example the result has to be args

I now wrote the following method:

public static String findWord(String text) {
String result = null;
boolean found = false;
for (int i = 0; i < text.length(); i++) {
for (int j = 0; j < text.length(); j++) {
String first = text.substring(0, i*j);
String last = text.substring(text.length() - i*j, text.length());
if (first.equals(last) && first.length() > 0) {
result = first;
found = true;
break;
}
}
if (found) {
break;
}
}
return result;
}


This seems to work for the test cases I tested, but I'm not sure if it works for all cases. Additionally, I'm not sure if there isn't a simpler solution. I need two loops and ugly break statements. So how could I improve that?

I'm not completely sure about the requirements, but what about the following?

public static String findWord2(final String text) {
for (int i = text.length() - 1; i > 0 ; i--) {
final String first = text.substring(0, i);
final String last = text.substring(text.length() - i);
if (first.equals(last)) {
return first;
}
}
return text;
}


Here are my tests:

import static org.junit.Assert.assertEquals;

import java.util.Arrays;
import java.util.Collection;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class FindWords2Test {

private final String expected;
private final String input;

public FindWords2Test(final String expected, final String input) {
this.expected = expected;
this.input = input;
}

@Parameters
public static Collection<String[]> data() {
//@formatter:off
final String[][] data = new String[][] {
{"file", "file = new JarFile(new File()\nSystem.out.println(file"},
{"file ", "file = new JarFile(new File()\nSystem.out.println(file "},
{"file = new JarFile(new File()\nSystem.out.println(",
"file = new JarFile(new File()\nSystem.out.println("},
{"args", "args"},
{"", ""},
{"a", "a"},
{"a", "aa"}};
//@formatter:on
return Arrays.asList(data);
}

@Test
public void testFindWords() throws Exception {
assertEquals(expected, FindWords2.findWord2(input));
}
}

• Wow, I never knew about that Parameterized runner. Looks quite useful. :) – ZeroOne May 12 '12 at 22:52

Firstly, if you are actually working with code, there is a good chance whatever you are doing would be better done with a real parser then whatever string hackery you are proposing.

Secondly, I believe your code will throw exceptions for "argst".

Thirdly, your problem need a bit better defining. There may be multiple substrings that exist at the beginning and end of the string. In any case, you always have the trivial empty string and the whole string. You need to define exactly which solution you are trying to find

public static String findWord(String text) {
String result = null;
boolean found = false;


You don't need two variables, just check if result == null

        for (int i = 0; i < text.length(); i++) {


I don't know why you included this outer loop. At any rate for i == 0, the inner loop never succeeds.

            for (int j = 0; j < text.length(); j++) {


This loop misses the case of the whole string. It should be j <= text.length()

                String first = text.substring(0, i*j);
String last = text.substring(text.length() - i*j, text.length());


If you elide the second parameter, it takes to the end of the list

                if (first.equals(last) && first.length() > 0) {


You can skip the second text by starting i and j at 1.

                    result = first;
found = true;
break;


Just return. It'll make the code much cleaner

                }
}
if (found) {
break;
}
}
return result;
}