¿Cómo podría separar una Cadena usando una Lista de Cadenas dada previamente, separándolas por espacios?
P.ej:
Lista de palabras: words = {"hello", "how", "are", "you"}
La cadena que quiero separar: text = "hellohowareyou"
public static String separateText(String text, List<String> words) { String new_text; for (String word : words) { if (text.startsWith(word)) { String suffix = text.substring(word.length()); //'suffix' is the 'text' without it's first word new_text += " " + word; //add the first word of the 'string' separateString(suffix, words); } } return new_text; } Y new_text debería devolver hello how are you
Tenga en cuenta que el orden de las words de la Lista podría ser diferente y también tener más palabras, como un diccionario.
¿Cómo podría hacer esta recursividad, si es necesario?
Esto debería hacer lo que quieras.
text , elimine una palabra a la vez y finalice cuando el text esté vacío public static String separateText(String text, List<String> words){ StringBuilder newTextBuilder = new StringBuilder(); outerLoop: while(text.length() > 0){ for(String word : words){ if(text.startsWith(word)){ newTextBuilder.append(word + " "); text = text.substring(word.length()); continue outerLoop; } } } return newTextBuilder.toString(); } }¿Cómo podría separar una Cadena usando una Lista de Cadenas dada previamente, separándolas por espacios?
Más o menos como ya empezaste. Verificando si el texto restante comienza con alguna de las palabras de la lista, elimine la palabra inicial y mantenga el sufijo.
Ya hiciste todo eso, pero en lugar de mantener el sufijo y seguir iterando, decidiste intentar llamar al texto separateText de forma recursiva.
Esa también es una posibilidad, pero incluso normalmente iterar en un ciclo while hasta que el sufijo (o el texto restante) esté vacío es suficiente.
Usar un bucle como while (index < text.length()) también funcionará para entradas más largas, incluso si las palabras están en un orden diferente.
public String separateText(String text, List<String> words){ if (text == null) return ""; if (words == null || words.isEmpty()) return text; StringBuilder sb = new StringBuilder(); boolean unknownWord = false; int index = 0; while (index < text.length()) { boolean wordFound = false; for (String word : words) { if (!word.isEmpty() && text.startsWith(word, index)) { wordFound = true; // move the index ahead just past the last letter of the word found index += word.length(); if (unknownWord) { unknownWord = false; sb.append(" "); } sb.append(word); sb.append(" "); break; } } if (!wordFound) { unknownWord = true; sb.append(text.charAt(index)); index++; } } return sb.toString(); }Para un método recursivo intente lo siguiente:
public static String separateText(String text, List<String> words){ return separateText(text, words, new StringBuilder()); } public static String separateText(String text, List<String> words, StringBuilder result){ for(String word : words){ if (text.startsWith(word)){ result.append(word).append(" "); text = text.substring(word.length()); ArrayList<String> newList = new ArrayList<>(words); newList.remove(word); separateText(text, newList, result); break; } } return result.toString().trim(); }Esta solución es bastante simple, pero no es óptima para la memoria, porque se crean muchas String nuevas.
public static String separate(String str, Set<String> words) { for (String word : words) str = str.replace(word, word + ' '); return str.trim(); }Manifestación
Set<String> words = Set.of("hello", "how", "are", "you"); System.out.println(separate("wow hellohowareyouhellohowareyou", words)); // wow hello how are you hello how are you Otra solución, con StringBuilder y me parece mejor desde la vista de rendimiento.
public static String separate(String str, Set<String> words) { List<String> res = new LinkedList<>(); StringBuilder buf = new StringBuilder(); for (int i = 0; i < str.length(); i++) { buf.append(str.charAt(i)); if (str.charAt(i) == ' ' || words.contains(buf.toString())) { res.add(buf.toString().trim()); buf.delete(0, buf.length()); } } return String.join(" ", res); }import java.util.*; public class Main { public static void main(String[] args) throws Exception { // You must sort this by it's length, or you will not have correct result // since it may cause match with more shorter words. // In this example, it's done List<String> words = Arrays.asList("hello", "how", "are", "you"); List<String> detectedWords = new ArrayList<>(); String text = "hellohowareyou"; int i = 0; while (i < text.length()) { Optional<String> wordOpt = Optional.empty(); for (String word : words) { if (text.indexOf(word, i) >= 0) { wordOpt = Optional.of(word); break; } } if (wordOpt.isPresent()) { String wordFound = wordOpt.get(); i += wordFound.length(); detectedWords.add(wordFound); } } String result = String.join(" ", detectedWords); System.out.println(result); } }Supuse:
null^(hello|how|are|you)$