Hallo alle Zusammen,
wie die Überschrift schon sagt, versuche ich in einem vorhandenen String ein ganzes Wort zu finden. Mit dem normallen IndexOf würde ich z.b. im folgenden Beispiel nicht das richtige Wort finden.
string TempString = "Hans wollte 40 km laufen, aber ab 20 km hatte er keine Puste mehr";
string s = "ab";
int Position = TempStringt.IndexOf(s);
Als Position erhalte ich hier das "ab" in "aber" und nicht das alleinstehende "ab".
Ich könnte zwar z.B. mit
if (!char.IsLetter(TempString[Position - 1]) && !char.IsLetter(TempString[Position + s.Length]))
{
}
selber prüfen, ob es sich um ein alleinstehendes Wort handelt, aber da ich die IndexOf-Methode ziemlich oft benutze, ist mir dieser Weg ein wenig zu umständlich.
Hat jemand einen Vorschlag wie ich das Problem lösen kann?
Hallo,
sowas lässt sich über Reguläre Ausdrücke sehr gut lösen. ([Artikel] Regex-Tutorial)
"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)
hmm... das Tutorial kenne ich schon.. weiß allerdings nicht wie ich das mit der IndexOf-Methode verbinden soll...
muss ich mir mal näher angucken... danke für den tipp^^
Hallo,
ohne Regex zu verwenden (wäre sicherlich besser) könntest du auch im "Suchstring" die Leerzeichen (welche ja ein Wort umgeben) verwenden.
string s = " ab ";
verwenden und dann den gefunden Index um 1 korrigieren. Allerdings musst du den Sonderfall wenn das Wort am Anfang steht behandeln.
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
Hallo gfoidl,
ich wüsste nicht, warum es besser sein sollte, hier kein Regex zu verwenden. Im Gegenteil, dein Workround hat diverse Nachteile:
Worte am Anfang und am Ende des Strings werden nicht gefunden.
Worte, die durch andere Whitespaces als Leerzeichen getrennt sind (z.B. Tab/CR/NL), also z.B. am Ende und am Anfang einer Zeile stehen, werden nicht gefunden.
Worte, hinter (oder vor) denen direkt Satzzeichen stehen, werden nicht gefunden.
All die Probleme hat man bei Regex und \b nicht.
herbivore
Hallo Cuin,
wenn du wirklich kein RegEx benutzen möchtest, könntest du auch string.split(" ") verwenden. Da bekommst du ein string[] mit je einem Wort an einer Array-Adresse zurück. Dann könntest du alle Arrayelemente auf dein Suchwort hin überprüfen.
Vielleicht ein weing umständlich aber sollte funktionieren.
Hallo Jochen1980,
das verursacht allerdings nahezu alle Probleme, die auch bei gfoidl Vorschlag entstehen. Ok, man könnte an allen White-Spaces splitten, dass würde wieder ein Problem beseitigen. Das mit den Satzzeichen würde allerdings bleiben. Und wenn man versucht, alle möglichen Sonderzeichen als Trennzeichen zu definieren, wird es spätestens abwegig.
Also doch lieber Regex nehmen.
herbivore
Erstmal danke für eure Tipps^^
@gfoidl: Wie herbivore schon erwähnte, ist das nicht wirklich eine passende methode, da ich ja dann alle möglichen Fälle abfangen müsste, was sicher mehr Aufwand wäre als meine eigene umständliche Lösung. Aber trotzdem Danke für den Tipp.
@Jochen1980: Genau das ist mein Problem^^
Ich habe nämlich einen Text bzw. Liedtext. Als erstes überprüfe ich ob sich das Schlüsselwort überhaupt in dem Lied befindet, das funktioniert mit meiner Methode auch super. Danach wird NUR der Vers in dem sich das Wort befindet an eine Methode weitergegben. Diese Methode splittet dann nochmal den Vers mit string.splitt(). Mein Problem ist jetzt, das ich mein Schlüsselwort wieder in dem string[] finden muss.
mit IndexOf("ab") würde ich ja nur das Wort "aber" findet.
Theoretisch hättte ich auch jedes Element im Array per String.compare mit meinem Schlüsselwort vergleichen können, da die Satzeichen aber noch vorhanden sind, funktioniert der vergleich nicht mehr.
Wörter wie "aber", "Haben" oder "Rabe" dürfen nicht gefunden werden"
Wörter mit Satzzeichen wie "ab," oder "ab!" hingegen schon.
Hiermal ein Codeausschnitt:
string[] splitter = Text.Split(new char[] { ' ', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
Bis jetzt habe ich noch keine Zeit gehabt, aber RegEx hört sich gut an. Ich versuche mal mein Problem damit zu lösen.
mfg Cuin
Ich hätte gfoidls post ja so verstanden, dass RegEx hier die bessere Lösung ist..
Wie herbivore schon sagte, das klappt ganz gut:
string input = "Hans wollte 40 km laufen, aber ab 20 km hatte er keine Puste mehr";
string wordToFind = "ab";
string regExWordDelimiter = "\\b";
Regex regEx = new Regex(wordToFind + regExWordDelimiter, RegexOptions.IgnoreCase | RegexOptions.Multiline);
IEnumerable matches = regEx.Matches(input);
foreach (Match match in matches)
{
System.Console.Write(match.Value + " ");
}
System.Console.ReadKey();
Hallo,
Ich hätte gfoidls post ja so verstanden, dass RegEx hier die bessere Lösung ist..
wenigsten einer hats vestanden, aber ich gebe zu dass ich das heute beim Lesen auch anders gesehen habe. Also hab ich das da sehr unglücklich formuliert. Gemeint war schon:
ohne Regex zu verwenden (Regex wäre sicherlich besser)
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
OK, das ist schon mal eine gute Basis, an dem Regex(...) muss man zwar noch basteln aber vom grundgerüst schonmal ein guter Ansatz.
Wenn man als input das hier nimmt:
string input = "Hans blickte runter ins Tal";
string wordToFind = "er";
dann findet er nämlich auch das "er" in "runter"....
Hi Cuin,
du hast das WordBoundary-Zeichen \b ja auch nur hinten angehängt.
Damit du das komplette Wort beschreibst, musst du schon an beiden Enden die WordBoundary setzen. Also häng vorn _und _ hinten das \b an.
beste Grüße
zommi
@zommi: Ich bin ja so doof^^ Ich habe das "\b" als backspace interpretiert^^
Ich habe mich schon gefragt, wieso man das wort "ab" in "Test ab," findet, da nach "ab" ja kein leerzeichen steht sondern ein komma...
ok, ich finde jetzt wirklich nur die substrings, die ich auch finden möchte! 😃
Vielen Dank für eure Hilfe.
Hier nochmal ein link, der mir erklärt hat, was das "\b" Zeichen bedeutet:
http://www.regular-expressions.info/wordboundaries.html
Zum Schluss hätte ich da aber noch eine Frage: Wäre es sinnvoll bzw. ist es möglich mit verhältnismäßigem Aufwand, die String.IndexOf methode mit hilfe der hier gefundenen Lösung so zu überschreiben, dass sie nur ganze Wörter sucht?
Zum Schluss hätte ich da aber noch eine Frage: Wäre es sinnvoll bzw. ist es möglich mit verhältnismäßigem Aufwand, die String.IndexOf methode mit hilfe der hier gefundenen Lösung so zu überschreiben, dass sie nur ganze Wörter sucht?
Du kannst natürlich eine neue Methode "IndexOfWord(...)" anbieten. Eventuell lohnt es sich für dich daraus eine Extension Method für die String-Klasse zu bauen.
Den Index (die Position) des gefundenen Wortes bekommst du über den deinen Match. Genauer gesagt mit Match.Index
.
beste Grüße
zommi
@zommi: Vielen Dank. Mit diesem Tipp habe ich jetzt endlich mein Problem lösen können^^
Hier die Lösung:
public static class HelperClass
{
public static int IndexOfWord(this string myString, string myWord)
{
int myIndex;
Regex myRegex = new Regex("\\b" + myWord + "\\b");
if ((myIndex = myRegex.Match(myString).Index) == 0)
{
if (myString.IndexOf(myWord) == 0)
{
return 0;
}
else
{
return -1;
}
}
else
{
return myIndex;
}
}
public static int IndexOfWord(this string myString, string myWord, int myPosition)
{
int myIndex;
Regex myRegex = new Regex("\\b" + myWord + "\\b");
if ((myIndex = myRegex.Match(myString, myPosition).Index) == 0)
{
if (myString.IndexOf(myWord, myPosition) == 0)
{
return 0;
}
else
{
return -1;
}
}
else
{
return myIndex;
}
}
}
Leider liefert Match.Index den Wert 0 anstatt -1 zurück, falls es das gesuchte Wort im String NICHT findet. Es kann natürlich auch sein, dass sich das Schlüsselwort an Position 0 befindet, deshalb muss man, falls Match.Index 0 liefert nochmal überprüfen ob IndexOf -1 liefert oder nicht.
Falls ja, dann befindet sich das gesuchte Wort definitiv nicht im String, anderfalls muss IndexOf 0 liefern, was bedeutet, dass sich das Wort an Position 0 befindet.
Vielen Dank an alle für eure schnelle und gute Hilfe!
mfg Cuin
Die Klasse Match hat auch eine Eigenschaft, die dir sagt ob auch wirklich gematcht wurde oder nicht und diese heißt "Success" oder ähnlich.
Lg XXX
Gute Idee^^ Ich sollte mal den Code bei gelegenheit umschreiben. thx
mfg Cuin
Regex rgx = new Regex("\b([a-zA-Z]+)\b");
var mtch = rgx.Match(myString);
if (mtch.Success) {
return mtch.Groups(1).Value;
}
Gibt das erste Wort zurück. Gebräuchlicher wäre aber wohl Regex.Matches.
@Cuin
Wenn du dein Regex dynamisch zusammenbaust, solltest du auf 2 Dinge achten:
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...
@kleines_eichhoernchen: Daran habe ich garnicht gedacht, dass die Satzzeichen in meinem übergebenen Wort als Regex-Token interpretiert werden. Das hätte zu unschönen Effekten geführt.
So, habe die Klasse nochmal umgeschrieben:
public static class HelperClass
{
private static Regex myRegex;
public static int IndexOfWord(this string myString, string myWord)
{
myRegex = new Regex("\\b" + Regex.Escape(myWord) + "\\b", RegexOptions.Compiled);
Match mtch = myRegex.Match(myString);
if (mtch.Success)
return mtch.Index;
else
return -1;
}
public static int IndexOfWord(this string myString, string myWord, int myPosition)
{
myRegex = new Regex("\\b" + Regex.Escape(myWord) + "\\b", RegexOptions.Compiled);
Match mtch = myRegex.Match(myString, myPosition);
if (mtch.Success)
return mtch.Index;
else
return -1;
}
Funktioniert so auch ganz gut und schaut auch besser aus^^
Den Satz verstehe ich allerdings noch nicht so ganz:
sondern die zurückgegebenen Matches entsprechend nochmal zu vergleichen.
Danke nochmals.^^
mfg Cuin
private static Regex myRegex; public static int IndexOfWord(this string myString, string myWord) { myRegex = new Regex("\\b" + Regex.Escape(myWord) + "\\b", RegexOptions.Compiled);
Ist nicht wirklich sehr sinnvoll.
Du erzeugst das Regex bei jedem Methodenaufruf neu - dann brauchst du es auch nicht in einem Feld speichern.
Also besser:
private static readonly Regex myRegex = new Regex("\\b" + Regex.Escape(myWord) + "\\b", RegexOptions.Compiled);
//Oder
Match match = Rgex.Match(/*pattern*/, myString);
private static readonly Regex myRegex = new Regex("\b" + Regex.Escape(myWord) + "\b", RegexOptions.Compiled);
//Oder
Match match = Rgex.Match(/pattern/, myString);
Bei mir kommt da eine Fehlermeldung:
Einem statischen, schreibgeschützten Feld kann nichts zugewiesen werden (außer in einem statischen Konstruktor oder einem Variableninitialisierer).
Dein zweites Beispiel funktioniert leider nicht, da es keine Regex.Match-Überladung gibt, in der man die Anfangsposition mit angeben kann. (Für meine zweite Methode).
mfg Cuin
Bei mir kommt da eine Fehlermeldung:
Das Zuweisen in den Methoden selbst musst du dann natürlich weglassen.
Achso, jetzt versteh ich^^
naja, funktioniert aber leider trotzdem nicht, da es ja keine match-überladung gibt, bei der man die anfangsposition mitangeben kann...