J'ai une chaîne que je dois analyser pour différents mots clés. Par exemple, j'ai la chaîne:
"Je viendrai te rencontrer au 123woods"
Et mes mots clés sont
'123woods' 'bois'
Je devrais signaler chaque fois que j'ai un match et où. Les occurrences multiples doivent également être prises en compte. Cependant, pour celui-ci, je ne devrais obtenir un match que sur 123woods, pas sur les bois. Cela élimine l'utilisation de la méthode String.contains (). De plus, je devrais pouvoir avoir une liste/un ensemble de mots clés et vérifier en même temps leur occurrence. Dans cet exemple, si j'ai "123woods" et "come", je devrais avoir deux occurrences. L'exécution de la méthode doit être quelque peu rapide sur les gros textes.
Mon idée est d'utiliser StringTokenizer mais je ne sais pas s'il fonctionnera bien. Aucune suggestion?
L'exemple ci-dessous est basé sur vos commentaires. Il utilise une liste de mots clés, qui sera recherchée dans une chaîne donnée en utilisant les limites de Word. Il utilise StringUtils d'Apache Commons Lang pour construire l'expression régulière et imprimer les groupes correspondants.
String text = "I will come and meet you at the woods 123woods and all the woods";
List<String> tokens = new ArrayList<String>();
tokens.add("123woods");
tokens.add("woods");
String patternString = "\\b(" + StringUtils.join(tokens, "|") + ")\\b";
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println(matcher.group(1));
}
Si vous recherchez plus de performances, vous pouvez jeter un œil à StringSearch : algorithmes de mise en correspondance de modèles hautes performances en Java.
Utilisez les limites regex + Word comme d'autres l'ont répondu.
"I will come and meet you at the 123woods".matches(".*\\b123woods\\b.*");
sera vrai.
"I will come and meet you at the 123woods".matches(".*\\bwoods\\b.*");
sera faux.
J'espère que cela fonctionne pour toi:
String string = "I will come and meet you at the 123woods";
String keyword = "123woods";
Boolean found = Arrays.asList(string.split(" ")).contains(keyword);
if(found){
System.out.println("Keyword matched the string");
}
Que diriez-vous de quelque chose comme Arrays.asList(String.split(" ")).contains("xx")
?
Voir String.split () et Comment puis-je tester si un tableau contient une certaine valeur .
Vous avez un moyen de matchWord exact from String dans Android:
String full = "Hello World. How are you ?";
String one = "Hell";
String two = "Hello";
String three = "are";
String four = "ar";
boolean is1 = isContainExactWord(full, one);
boolean is2 = isContainExactWord(full, two);
boolean is3 = isContainExactWord(full, three);
boolean is4 = isContainExactWord(full, four);
Log.i("Contains Result", is1+"-"+is2+"-"+is3+"-"+is4);
Result: false-true-true-false
Fonction pour match Word:
private boolean isContainExactWord(String fullString, String partWord){
String pattern = "\\b"+partWord+"\\b";
Pattern p=Pattern.compile(pattern);
Matcher m=p.matcher(fullString);
return m.find();
}
Terminé
Essayez de faire correspondre les expressions régulières. Correspondance pour "\ b123wood\b",\b est un saut de mot.
La solution semble être acceptée depuis longtemps, mais la solution pourrait être améliorée, donc si quelqu'un a un problème similaire:
Il s'agit d'une application classique pour les algorithmes de recherche à motifs multiples.
Recherche de modèles Java (avec Matcher.find
) n'est pas qualifié pour cela. La recherche d'un mot clé exactement est optimisée en Java, la recherche d'une expression or utilise l'automate non déterministe regex qui revient en arrière sur les décalages. Dans le pire des cas, chaque caractère du texte sera traité l fois (où l est la somme des longueurs de motif).
La recherche de modèle unique est meilleure, mais pas qualifiée aussi. Il faudra commencer la recherche entière pour chaque modèle de mot-clé. Dans le pire des cas, chaque caractère du texte sera traité p fois où p est le nombre de motifs.
La recherche à motifs multiples traitera chaque caractère du texte exactement une fois. Les algorithmes appropriés pour une telle recherche seraient Aho-Corasick, Wu-Manber ou Set Backwards Oracle Matching. Ceux-ci peuvent être trouvés dans des bibliothèques comme Stringsearchallgorithms ou byteseek .
// example with StringSearchAlgorithms
AhoCorasick stringSearch = new AhoCorasick(asList("123woods", "woods"));
CharProvider text = new StringCharProvider("I will come and meet you at the woods 123woods and all the woods", 0);
StringFinder Finder = stringSearch.createFinder(text);
List<StringMatch> all = Finder.findAll();
Une façon beaucoup plus simple de le faire est d'utiliser split ():
String match = "123woods";
String text = "I will come and meet you at the 123woods";
String[] sentence = text.split();
for(String Word: sentence)
{
if(Word.equals(match))
return true;
}
return false;
C'est une façon plus simple et moins élégante de faire la même chose sans utiliser de jetons, etc.
public class FindTextInLine {
String match = "123woods";
String text = "I will come and meet you at the 123woods";
public void findText () {
if (text.contains(match)) {
System.out.println("Keyword matched the string" );
}
}
}
Vous pouvez utiliser des expressions régulières. Utilisez les méthodes Matcher et Pattern pour obtenir la sortie souhaitée
En repensant à la question d'origine, nous devons trouver des mots clés donnés dans une phrase donnée, compter le nombre d'occurrences et savoir où. Je ne comprends pas très bien ce que signifie "où" (est-ce un index dans la phrase?), Donc je vais passer celui-là ... J'apprends toujours Java, une étape à la fois, donc je vais voir à celui-là en temps voulu :-)
Il faut noter que les phrases courantes (comme celle de la question d'origine) peuvent avoir des mots-clés répétés, donc la recherche ne peut pas simplement demander si un mot-clé donné "existe ou non" et le compter comme 1 s'il existe. Il peut y en avoir plus d'un. Par exemple:
// Base sentence (added punctuation, to make it more interesting):
String sentence = "Say that 123 of us will come by and meet you, "
+ "say, at the woods of 123woods.";
// Split it (punctuation taken in consideration, as well):
Java.util.List<String> strings =
Java.util.Arrays.asList(sentence.split(" |,|\\."));
// My keywords:
Java.util.ArrayList<String> keywords = new Java.util.ArrayList<>();
keywords.add("123woods");
keywords.add("come");
keywords.add("you");
keywords.add("say");
En le regardant, le résultat attendu serait 5 pour "Say" + "come" + "you" + "say" + "123woods", en comptant "say" deux fois si nous allons en minuscules. Si nous ne le faisons pas, alors le nombre devrait être de 4, "Say" étant exclu et "say" inclus. Bien. Ma suggestion est:
// Set... ready...?
int counter = 0;
// Go!
for(String s : strings)
{
// Asking if the sentence exists in the keywords, not the other
// around, to find repeated keywords in the sentence.
Boolean found = keywords.contains(s.toLowerCase());
if(found)
{
counter ++;
System.out.println("Found: " + s);
}
}
// Statistics:
if (counter > 0)
{
System.out.println("In sentence: " + sentence + "\n"
+ "Count: " + counter);
}
Et les résultats sont:
Trouvé: Dites
Trouvé: venez
Je t'ai trouvé
Trouvé: dites
Trouvé: 123woods
Dans la phrase: Dites que 123 d'entre nous viendront vous rencontrer, disons, dans les bois de 123woods.
Nombre: 5
Vous pouvez également utiliser la correspondance d'expression régulière avec le drapeau\b (limite de Word entière).
Pour faire correspondre "123woods" au lieu de "woods", utilisez le groupement atomique dans une expression régulière. Une chose à noter est que, dans une chaîne correspondant uniquement à "123woods", elle correspondra au premier "123woods" et se terminera au lieu de rechercher plus avant la même chaîne.
\b(?>123woods|woods)\b
il recherche 123woods comme recherche principale, une fois qu'il a été trouvé, il quitte la recherche.