Ich habe schon wieder etwas im Internet bestellt: Etwas Praktisches für die Küche: High Heels. Damit ich oben ans Gewürzregal rankomme.

So schwierig kann das wohl nicht sein, dachte ich. Und probierte es. Allerdings: die Lösung des Problems war doch komplizierter als gedacht.

Vor einigen Jahren hatte ich die Aufgabe in einer sehr großen Excelliste (zirka 60.000 Zeilen) die Daten „zu putzen“. Mitarbeiterinnen und Mitarbeiter hatten an unterschiedlichen Stellen in einer Spalte Informationen eingetragen – allerdings mehrere Informationen getrennt durch Trennzeichen. Durch verschiedene Trennzeichen – mal ein „/“, mal ein Semikolon, mal ein „:::“, mal ein „-„:

Ich habe damals einige VBA-Makros geschrieben, um die Daten „zu putzen“. Ich frage mich, ob man sie mit PowerQuery bereinigen kann. Man kann!

Ich erstelle eine Liste der Trennzeichen:

Ich importiere die Daten und trenne die Liste „hart“ an einem Zeichen:

Der Befehl

= Table.SplitColumn(#"Geänderter Typ", "PK", Splitter.SplitTextByDelimiter("_", QuoteStyle.Csv), {"PK.1", "PK.2", "PK.3"})

trennt die Spalte. Wie kann man alle Trennzeichen verwenden? Ich importiere die Trennzeichenliste und wandle sie in über Transformieren / In Liste konvertieren in eine Liste um:

Kann SplitTextByDelimiter meine tbl_Trennzeichen verarbeiten? Nein!

Ich gehe auf die Suche:

SplitTextByAnyDelimiter kann die Liste verarbeiten:

= Table.SplitColumn(#"Geänderter Typ", "PK", Splitter.SplitTextByAnyDelimiter(tbl_Trennzeichen), {"PK.1", "PK.2", "PK.3"})

Jedoch: {„PK.1“, „PK.2“, „PK.3“} legt fest, dass DREI neue Spalten geliefert werden mit den Namen „PK.1“, „PK.2“ und „PK.3“. Ich probiere aus:

= Table.SplitColumn(#"Geänderter Typ", "PK", Splitter.SplitTextByAnyDelimiter(tbl_Trennzeichen), {"PK.1", "PK.2", "PK.3", "PK.98", "PK.99"})

Klappt! Ich erhalte weitere Spalten:

Allerdings: Wie viele Spalten entstehen denn? Ich versuche es ohne den letzten Parameter:

= Table.SplitColumn(#"Geänderter Typ", "PK", Splitter.SplitTextByAnyDelimiter(tbl_Trennzeichen))

Und erhalte EINE neue Spalte:

Schlecht! Ich schaue den Parameter genauer an – er heißt:

columnNamesOrNumber

Also versuche ich eine Zahl. Ich beginne bei 99:

Der linke Teil sieht vielversprechend aus:

– der rechte nicht:

Ich überlege: ich muss berechnen wie viele neue Spalten erzeugt werden. Ich muss berechnen wie oft die Trennzeichen der Liste tbl_Trennzeichen in jedem der Texte vorkommt.

Leider stellt PowerQuery keine Funktion zur Verfügung, mit deren Hilfe man die Anzahl der vorkommenden Zeichen in einer anderen Zeichenkette ermitteln kann. So etwas berechne ich (auch in Excel) immer wie folgt:

Länge(Zeichenkette) - Länge(Zeichenkette ohne gesuchten Zeichen)

oder

Länge(Zeichenkette) - Länge(Ersetze(Zeichenkette; gesuchten Zeichen))

Eine PowerQuery-Abfrage muss her:

(Text.Length(Text) - 
                Text.Length(Text.Replace(Text -

Ich überlege: minus jedes Element der Liste. Also genauer:

(Text as text) =>

     List.Accumulate(
         tbl_Trennzeichen,
         0,
         (state, current) => 
            state + 
                (Text.Length(Text) - 
                Text.Length(Text.Replace(Text, current, ""))) 
    ) 

Ich muss die Anzahl kumulieren. Der Befehl List.Accumulate tut gute Dienste. Er möchte eine Liste haben (tbl_Trennzeichen), einen Beginn (0) und eine Funktion. Diese Funktion erhält zwei Teile:

(state, current)

Die Variable state „merkt“ sich die Zahl, current greift auf jede Zeile zu. Allerdings darf ich nicht einfach die Differenz aus Länge vorher und Länge nachher bilden:

Text.Length(Text) - 
                Text.Length(Text.Replace(Text, current, ""))

sondern muss durch die Länge teilen. Also wenn ich von der Länge

Hallo:::ich:::bin:::es:::wieder

31 die ::: entferne:

Halloichbineswieder

bleiben 19 Zeichen. Differenz = 12. Da aber nur vier Mal das ::: auftaucht, muss ich es noch durch die Länge teilen, also:

(Text.Length(Text) - 
                Text.Length(Text.Replace(Text, current, ""))) 
                / Text.Length(current)

Und schließlich: Wenn ich in ich-will-das zwei Bindestriche finde, erhalte ich nach dem Trennen DREI Teile.

Die komplette Funktion, die ich fxAnzahlTrennzeichen nenne sieht dann so aus:

(Text as text) =>

     List.Accumulate(
         tbl_Trennzeichen,
         0,
         (state, current) => 
            state + 
                (Text.Length(Text) - 
                Text.Length(Text.Replace(Text, current, ""))) 
                / Text.Length(current)
    ) + 1

Und kann verwendet werden:

Von dieser Spalte wird das Maximum berechnet und über ein Drilldown als Zahl „gespeichert“ (MAXZeichen):

Ein Klick auf fx und ein Bezug wird zu einem vorhergehenden Schritt hergestellt:

= #"Geänderter Typ"

Dort wird getrennt:

= Table.SplitColumn(Benutzerdefiniert1, "PK", Splitter.SplitTextByAnyDelimiter(tbl_Trennzeichen), MAXZeichen )

Und in Excel:

Probe aufs Exempel – ich trage in der Liste den folgenden Text ein:

A-B-C-D-E-F-G-H-I

und aktualisiere:

Klappt!

Witzig – noch während des Schreibens und Zwischenspeichern erhalte ich die Info, dass Oz du Soleil (zeitgleich mit mir) auch eine Lösung gepostet hat:

https://www.youtube.com/watch?v=EiHDsZxJ_EI

Er beschreitet einen ganz anderen Weg …

One comment

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.