{"id":431,"date":"2021-05-01T08:00:00","date_gmt":"2021-05-01T06:00:00","guid":{"rendered":"https:\/\/pascal-korz.de\/blog\/?p=431"},"modified":"2021-05-16T15:25:31","modified_gmt":"2021-05-16T13:25:31","slug":"powershell-fallen-2-substrings-in-strings-suchen","status":"publish","type":"post","link":"https:\/\/pascal-korz.de\/blog\/2021\/05\/01\/powershell-fallen-2-substrings-in-strings-suchen\/","title":{"rendered":"PowerShell-Fallen #2: Substrings in Strings suchen"},"content":{"rendered":"\n<p>Oft m\u00f6chte man pr\u00fcfen, ob ein String eine bestimmte Zeichenkette enth\u00e4lt \u2013 am besten unabh\u00e4ngig von der Gro\u00df- und Kleinschreibung. Und wenn sich ein PowerShell-Neuling mit den M\u00f6glichkeiten befasst, st\u00f6\u00dft er schnell auf die vielen Vergleichsoperatoren, darunter <code>contains<\/code> und auch viele andere, die mit einem i wie in case-<strong>i<\/strong>nsensitive beginnen. Es gibt sogar <code>icontains<\/code>, also genau das, was wir suchen, nicht wahr?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wie es nicht geht: -contains, -ccontains und -icontains<\/h2>\n\n\n\n<p>Zun\u00e4chst einmal unterscheiden <code>contains <\/code>und <code>icontains<\/code> beide nicht zwischen Gro\u00df- und Kleinschreibung. Wer das m\u00f6chte, greift stattdessen auf <code>ccontains<\/code> mit c wie <strong>c<\/strong>ase-sensitive zur\u00fcck.<\/p>\n\n\n\n<p>Probieren wir beide aus:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"It's a trap!\" -ccontains \"trap\"\n\"It's a trap!\" -icontains \"it\"\n\nOutput:\nFalse\nFalse<\/code><\/pre>\n\n\n\n<p>Offensichtlich enth\u00e4lt das Beispiel sowohl &#8222;trap&#8220; als auch ein gro\u00dfgeschriebenes &#8222;it&#8220;, und trotzdem findet PowerShell sie nicht. Der Grund daf\u00fcr ist einfach: Die beiden Operatoren wirken nicht auf Strings, sondern auf Arrays \u2013 und da wir nur einen String angegeben haben, konvertiert PowerShell ihn implizit in einen Array und sucht nun in diesem Array, das aus einem einzigen Element besteht, erfolglos nach einem Element &#8222;trap&#8220; beziehungsweise &#8222;it&#8220; (gro\u00df- oder kleingeschrieben).<\/p>\n\n\n\n<p>Klarer wird die Funktionsweise anhand folgender Beispielen:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"It's\", \"a\", \"trap\", \"!\" -ccontains \"trap\"\n\"It's a trap!\" -icontains \"it's a trap!\"\n\nOutput:\nTrue\nTrue<\/code><\/pre>\n\n\n\n<p>Im ersten Beispiel suchen wir tats\u00e4chlich in einem Array aus vier Elementen, und eines davon ist &#8222;trap&#8220;, darum ist der Vergleich wahr. Im zweiten Beispiel wird der String wieder in ein Array aus einem Element umgewandelt, aber der schreibungsunabh\u00e4ngige Vergleich ist trotzdem wahr, weil wir genau diesen String (unabh\u00e4ngig von Gro\u00df- und Kleinschreibung) suchen.<\/p>\n\n\n\n<p>Jetzt wissen wir, wie diese Vergleichsoperatoren funktionieren \u2013 aber wir wissen auch, dass sie ungeeignet sind, einen Substring in einem String zu finden. Welche M\u00f6glichkeiten haben wir also dann?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">M\u00f6glichkeit 1: Contains-Methode<\/h2>\n\n\n\n<p>Die gute Nachricht ist, dass Strings in PowerShell Objekte sind und eine eigene Methode namens <code>Contains<\/code> mitbringen. Erfolg!<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"It's a trap!\".Contains(\"It\")\n\nOutput:\nTrue<\/code><\/pre>\n\n\n\n<p>Leider h\u00e4lt diese Methode sich aber strikt an Gro\u00df- und Kleinschreibung, weshalb Folgendes leider nicht wie gew\u00fcnscht klappt:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"It's a trap!\".Contains(\"it\")\n\nOutput:\nFalse<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">M\u00f6glichkeit 2: regul\u00e4rer Ausdruck<\/h2>\n\n\n\n<p>Selbst viele erfahrene Programmierer scheuen vor <em>regular expressions<\/em> (RegEx) zur\u00fcck, obwohl das sehr schade ist. In diesem Fall l\u00f6sen sie das Problem sehr einfach und elegant, ohne kompliziert zu sein:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"It's a trap!\" -imatch \"it\"\n\nOutput:\nTrue<\/code><\/pre>\n\n\n\n<p>Das ist sogar der k\u00fcrzeste Befehl auf dieser Seite. Hier wird der Vergleichsoperator <code>imatch<\/code> (oder <code>match<\/code>, aber ich bevorzuge die explizite Variante) mit dem Suchmuster &#8222;it&#8220; eingesetzt.<\/p>\n\n\n\n<p>Man k\u00f6nnte sogar mit einem einzigen Befehl pr\u00fcfen, ob &#8222;it&#8220; oder &#8222;trap&#8220; beide in dem String enthalten sind:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"It's a trap!\" -imatch \"it|trap\"\n\nOutput:\nTrue<\/code><\/pre>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Oft m\u00f6chte man pr\u00fcfen, ob ein String eine bestimmte Zeichenkette enth\u00e4lt \u2013 am besten unabh\u00e4ngig von der Gro\u00df- und Kleinschreibung. Und wenn sich ein PowerShell-Neuling mit den M\u00f6glichkeiten befasst, st\u00f6\u00dft er schnell auf die vielen Vergleichsoperatoren, darunter contains und auch viele andere, die mit einem i wie in case-insensitive beginnen. Es gibt sogar icontains, also&hellip; <a class=\"more-link\" href=\"https:\/\/pascal-korz.de\/blog\/2021\/05\/01\/powershell-fallen-2-substrings-in-strings-suchen\/\"><span class=\"screen-reader-text\">PowerShell-Fallen #2: Substrings in Strings suchen<\/span> weiterlesen<\/a><\/p>\n","protected":false},"author":6,"featured_media":429,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-431","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell","entry"],"_links":{"self":[{"href":"https:\/\/pascal-korz.de\/blog\/wp-json\/wp\/v2\/posts\/431","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pascal-korz.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pascal-korz.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pascal-korz.de\/blog\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/pascal-korz.de\/blog\/wp-json\/wp\/v2\/comments?post=431"}],"version-history":[{"count":2,"href":"https:\/\/pascal-korz.de\/blog\/wp-json\/wp\/v2\/posts\/431\/revisions"}],"predecessor-version":[{"id":512,"href":"https:\/\/pascal-korz.de\/blog\/wp-json\/wp\/v2\/posts\/431\/revisions\/512"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/pascal-korz.de\/blog\/wp-json\/wp\/v2\/media\/429"}],"wp:attachment":[{"href":"https:\/\/pascal-korz.de\/blog\/wp-json\/wp\/v2\/media?parent=431"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pascal-korz.de\/blog\/wp-json\/wp\/v2\/categories?post=431"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pascal-korz.de\/blog\/wp-json\/wp\/v2\/tags?post=431"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}