Ваша проблема на самом деле не в строке кода:
puzzleDup = puzzleDup.substring(j + 1, puzzleDup.length());
, а в том, что вы перебираете неправильную строку головоломки в двух определенных местах (циклах) в вашем коде.Давайте возьмем второй внутренний цикл FOR в первом наборе циклов:
for(j = 0; j < puzzleLength; j++) {
if(wordstoFind[k].charAt(l) == puzzleDup.charAt(j)) {
ifWordExists++;
puzzleDup = puzzleDup.substring(j + 1, puzzleDup.length());
break;
}
}
Здесь вы перебираете длину исходной строки головоломки, но высравнение символов из фактического слова с символами в строке puzzleDup .Сначала переменная puzzleDup будет содержать исходное содержимое фактической строки головоломки, но в том же цикле вы удаляете все найденные символы, которые будут соответствовать символу из проверяемого слова .Делая это удаление, он уменьшает длину puzzleDup , и потому что Puzzle String будет длиннее, чем puzzleDup будет целочисленной переменной j в конечном итоге выйдет за пределы того, что puzzleDup способно обработать, поэтому генерирует StringIndexOutOfBoundsException .
Нижняя строка .... если вы собираетесь сравнивать слово символов с puzzleDup символов и затем изменять puzzleDup во время процессазатем используйте puzzleDup в объявлении цикла:
for (int j = 0; j < puzzleDup.length(); j++) {
if (wordstoFind[k].charAt(l) == puzzleDup.charAt(j)) {
ifWordExists++;
puzzleDup = puzzleDup.substring(j + 1, puzzleDup.length());
break;
}
}
С другой стороны, следующая строка кода
puzzleDup = puzzleDup.substring(j + 1, puzzleDup.length());
на самом деле не настолько эффективна, если только не первый символиз puzzleDup всегда будет сравниваемым персонажем из word .Что произойдет, если это 3-й персонаж в puzzleDup ?Затем вы стираете первые три символа, содержащиеся в puzzleDup ?Что если один из символов, который вы только что удалили, необходим для следующего слова символа?Я полагаю, что идея состоит в том, чтобы удалить только определенный символ в puzzleDup , который соответствует текущему символу word .Эта строка должна быть:
puzzleDup = puzzleDup.substring(0, j) + puzzleDup.substring(j + 1);
Эта строка кода удалит из puzzleDup только символ, равный символу из слова, обрабатываемого в данный момент.Теперь все остальные персонажи остаются в puzzleDup , чтобы иметь возможность сравниваться с ними.Весь внутренний цикл действительно должен выглядеть следующим образом:
for (int j = 0; j < puzzleDup.length(); j++) {
if (wordstoFind[k].charAt(l) == puzzleDup.charAt(j)) {
ifWordExists++;
puzzleDup = puzzleDup.substring(0, j) + puzzleDup.substring(j + 1);
break;
}
}
И в вашем другом наборе циклов FOR, далее в коде, второй внутренний цикл FOR долженвыглядят примерно так:
for (int j = puzzleDup.length() - 1; j > 0; j--) {
if (wordstoFind[k].charAt(l) == puzzleDup.charAt(j)) {
ifWordExists++;
puzzleDup = puzzleDup.substring(0, j-1) + puzzleDup.substring(j);
break;
}
}
Ниже я приведу метод, который может продемонстрировать один из способов выполнения этой конкретной задачи.В этом примере вы предоставляете запятую (,) с разделителем *, 1080 * Words String (так же, как вы уже сделали с примером кода), а также вы предоставляете строку головоломки.Метод возвращает коллекцию List, в которой каждый элемент этого списка будет содержать:
- Строка, содержащая фактическую перетасованную строку головоломки;
- Строка тире (-) к тому жедлина строки головоломки, за исключением того, что совпадающие символы из озадаченной строки и символы из обрабатываемого слова также находятся внутри строки, указывающей, где именно в строке головоломки были найдены совпадения;
- строка, содержащая фактическиеСлово, относящееся к вышеуказанному результату.
Вот метод:
public static List<String> findWordsInString(String wordsToLocate, String inputOrPuzzleString) {
List<String> resultsList = new ArrayList<>();
// With the following split regex, it doesn't matter
// how the words are comma delimited with regards to
// spacing.
String[] wordstoFind = wordsToLocate.split("\\s{0,},\\s{0,}");
List<String> foundCharList;
for (int k = 0; k < wordstoFind.length; k++) {
String libWord = wordstoFind[k];
/* The following flag is used to prevent a word from being
found twice within the Puzzle String at different locations.
If you actually want this feature then comment the below line
and any code lines related to it. */
boolean wordFound = false;
foundCharList = new ArrayList<>();
for (int l = 0; l < libWord.length(); l++) {
for (int j = 0; j < inputOrPuzzleString.length(); j++) {
if (libWord.charAt(l) == inputOrPuzzleString.charAt(j)) {
// Found a character. Add it and its puzzle index (delimited with a Pipe character) to foundChar.
String foundChar = inputOrPuzzleString.substring(j, (j + 1)) + "|" + String.valueOf(j);
/* Make sure the Character at Index isn't already in foundCharList.
We're not allowed to use the same character at the same puzzle
index more than once in any given word. */
boolean alreadyHave = false;
for (String str : foundCharList) {
if (str.equals(foundChar)) {
alreadyHave = true;
break;
}
}
/* Make sure we need the character and it won't be a duplicate to the
word makeup. We do this by removing all the characters we've already
found from a copy of the word we're working on then see which characters
are remaining. If the current character matches one of the remaining
then it's good to keep. */
String tmpWord = libWord;
for (String strg : foundCharList) {
for (int x = 0; x < tmpWord.length(); x++) {
if (strg.split("\\|")[0].equals(tmpWord.substring(x, x + 1))) {
tmpWord = tmpWord.substring(0, x) + tmpWord.substring(x + 1);
break;
}
}
}
if (tmpWord.contains(Character.toString(inputOrPuzzleString.charAt(j))) && !alreadyHave) {
foundCharList.add(foundChar);
}
}
if (foundCharList.size() == libWord.length()) {
resultsList.add(showWordMakeupInString(foundCharList, libWord, inputOrPuzzleString));
foundCharList.clear();
wordFound = true;
break;
}
if (wordFound) {
break;
}
}
}
}
return resultsList;
}
Этот метод также требует использования метода-сателлита ** showWordMakeupInString (), который устанавливает строки строкбыть помещенным в возвращенный список.Конечно, вы можете изменить все это так, как вам нравится:
public static String showWordMakeupInString(List<String> list, String word, String puzzleString) {
String ls = System.lineSeparator();
String resultString = puzzleString + ls;
String locations = String.join("", Collections.nCopies(puzzleString.length(), "-"));
for (int i = 0; i < list.size(); i++) {
String[] parts = list.get(i).split("\\|");
char letter = parts[0].charAt(0);
int atIndex = Integer.parseInt(parts[1]);
char[] puzzleChars = locations.toCharArray();
puzzleChars[atIndex] = letter;
locations = String.valueOf(puzzleChars);
}
resultString += locations + ls + word + ls;
return resultString;
}
Чтобы использовать этот метод, вы можете сделать что-то вроде этого:
// Create the WORD String...
String wordsToFind = "TEST,SAMPLE,OUTPUT,DOG,poop,HELLO,Who's Your Daddy";
// Create the PUZZLE String. Copy the WORD string and
// paste it below then delete all the commas.
String puzzle = "TESTSAMPLEOUTPUTpoopHELLODOGWho's Your Daddy";
// Shuffle the PUZZLE String...really mix it up :)
// The shuffleString() method is provided below.
puzzle = shuffleString(puzzle);
// Find the words within the WORD String within the PUZZLE String.
List<String> resultsList = findWordsInString(wordsToFind, puzzle);
// Display the Listed results to Console Window.
for(String strg : resultsList) {
System.out.println(strg);
}
Если вы запустите приведенный выше пример, вотчто вы должны увидеть в окне консоли:
OoEUWSOL oPOYpT'GAsTEdToaEdLp TyUoSDHPruLhDM
--E--S--------T----T------------------------
TEST
OoEUWSOL oPOYpT'GAsTEdToaEdLp TyUoSDHPruLhDM
--E--S-L--P------A-------------------------M
SAMPLE
OoEUWSOL oPOYpT'GAsTEdToaEdLp TyUoSDHPruLhDM
O--U------P---T----T------------U-----------
OUTPUT
OoEUWSOL oPOYpT'GAsTEdToaEdLp TyUoSDHPruLhDM
O---------------G------------------D--------
DOG
OoEUWSOL oPOYpT'GAsTEdToaEdLp TyUoSDHPruLhDM
-o-------o---p--------------p---------------
poop
OoEUWSOL oPOYpT'GAsTEdToaEdLp TyUoSDHPruLhDM
O-E----L-------------------L--------H-------
HELLO
OoEUWSOL oPOYpT'GAsTEdToaEdLp TyUoSDHPruLhDM
-o--W--- o--Y--'--s--d--a-d-- -y---D--ru-h--
Who's Your Daddy
Ваши результаты, конечно, будут немного отличаться, потому что строка PUZZLE всегда перетасовывается по-разному при каждом запуске.
shuffleString () метод:
public String shuffleString(String input) {
List<Character> characters = new ArrayList<>();
for (char c : input.toCharArray()) {
characters.add(c);
}
StringBuilder output = new StringBuilder(input.length());
while (!characters.isEmpty()) {
int randChar = (int) (Math.random() * characters.size());
output.append(characters.remove(randChar));
}
return output.toString();
}