Nur in bestimmtem Fall den String trennen

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Nur in bestimmtem Fall den String trennen

    Hallo Leute,

    ich habe eine Formel/Zeichenkette wie diese:

    Quellcode

    1. ​5,20 * 2,62 + 1,99 * 2,62 + 0,44 * 2,62 + 0,66 * 2,62 + 3,69 * 2,62 + 0,21 * ((2,62 + 2,62) / 2) + 0,77 * 2,62 + 0,22 * 2,62 + 0,30 * ((2,62 + 2,62) / 2) + 2,67 * 2,62


    Aktuell trenne ich diese Formel immer am "+" in Einzelstrings auf:

    Beispiel

    Quellcode

    1. ​NSArray *parts = [myString componentsSeparatedByString:@"+"];


    Ich würde diese Aufspliitung nun ganz gerne an eine Bedinung knüpfen, welche da wäre:
    => Wenn das "+" innerhalb eines Klammerpaares steht, darf der String dort nicht getrennt werden.

    Gewünschtes Ergebnis wäre dieses:

    Quellcode

    1. ​5,20 * 2,62
    2. + 1,99 * 2,62
    3. + 0,44 * 2,62
    4. + 0,66 * 2,62
    5. + 3,69 * 2,62
    6. + 0,21 * ((2,62 + 2,62) / 2)
    7. + 0,77 * 2,62
    8. + 0,22 * 2,62
    9. + 0,30 * ((2,62 + 2,62) / 2)
    10. + 2,67 * 2,62


    Ich denke auch hier geht es wieder in Richtung einer NSScanner Lösung?! Hätte da eventuell noch mal jemand einen Denkanstoß für mich? :(
    Man kann alles schaffen. Man muss es nur wollen ;)
    www.regetskcob.github.io
  • gritsch schrieb:

    es gibt auch fertige formelparser.


    macmoonshine schrieb:

    Ja, genau. Sehr nett ist beispielsweise dieser Artikel zu dem Thema.


    Danke für die Antworten und den Link!

    Ich würde aber behaupten, das ein Formelparser zum Trennen der Zeilen etwas overpowered wäre? Ich schaue aber mal in den Artikel rein, um eine etwas abgespecktere Version zu implementieren.
    Man kann alles schaffen. Man muss es nur wollen ;)
    www.regetskcob.github.io
  • Wenn Du nur die Untersuchung des Strings auf + und Klammern hast, dann sollte ein Scanner die einfachere und schnellere Lösung sein.

    Scanne dazu einfach bis zu jedem +, ( und ). Ist es eine ( erhöhst Du einen Zähler. Bei einer ) verringerst Du diesen Zähler. Kommt ein + und der Zähler ist auf 0 kannst Du einen Zeilenumbruch im Ergebnis String einsetzen, anderenfalls geht es einfach weiter.

    Sollte sich mit etwa 5-10 Zeilen Code realisieren lassen.
  • Bin jetzt gerade so weit:

    Quellcode

    1. ​+ (NSArray *)GetMasskettenZeilenGetrennt:(NSString *)masskette
    2. {
    3. NSMutableArray *rows = [NSMutableArray new];
    4. int bracketLevel = 0;
    5. NSLog(@"[+]Scanner - initiated with \n%@", masskette);
    6. masskette = [masskette stringByReplacingOccurrencesOfString:@"\r\n" withString:@""];
    7. NSScanner *scanner = [NSScanner scannerWithString:masskette];
    8. while (![scanner isAtEnd]) {
    9. NSString *row = nil;
    10. if ([scanner scanString:@"(" intoString:NULL]) {
    11. bracketLevel++;
    12. }
    13. else if ([scanner scanString:@")" intoString:NULL]) {
    14. bracketLevel--;
    15. }
    16. NSLog(@"[+]Scanner - bracketLevel:%i", bracketLevel);
    17. if (bracketLevel == 0) {
    18. [scanner scanUpToString:@"+" intoString:&row];
    19. }
    20. NSLog(@"[+]Scanner - scanned row '%@'", row);
    21. }
    22. return rows;
    23. }
    Alles anzeigen


    Ausgabe ist dann aber:

    Quellcode

    1. ​2014-06-30 10:29:51.041 Raumaufmass[3538:60b] [+]Scanner - initiated with
    2. 0,21 m * ((2,62 m
    3. + 2,62 m) / 2)
    4. 2014-06-30 10:29:51.041 Raumaufmass[3538:60b] [+]Scanner - bracketLevel:0
    5. 2014-06-30 10:29:51.041 Raumaufmass[3538:60b] [+]Scanner - scanned row '0,21 m * ((2,62 m'
    6. 2014-06-30 10:29:51.042 Raumaufmass[3538:60b] [+]Scanner - bracketLevel:0
    7. 2014-06-30 10:29:51.042 Raumaufmass[3538:60b] [+]Scanner - scanned row '(null)'


    Hatjemand eine Idee wieso er trotzdem nicht weiter scannt? Also wieso das Bracket-Level auf 0 ist?
    Man kann alles schaffen. Man muss es nur wollen ;)
    www.regetskcob.github.io
  • Ich glaube, ich denke immernoch völlig am Ziel vorbei...

    Quellcode

    1. + (NSArray *)GetMasskettenZeilenGetrennt:(NSString *)masskette
    2. {
    3. NSMutableArray *rows = [NSMutableArray new];
    4. int bracketLevel = -1;
    5. masskette = [masskette stringByReplacingOccurrencesOfString:@"\r\n" withString:@""];
    6. NSLog(@"Masskette:%@", masskette);
    7. NSScanner *scanner = [NSScanner scannerWithString:masskette];
    8. while (![scanner isAtEnd]) {
    9. NSMutableString *row = [NSMutableString new];
    10. // Öffnende Klammer suchen
    11. if ([scanner scanString:@"(" intoString:NULL]) {
    12. bracketLevel++;
    13. }
    14. // Schließende Klammer suchen
    15. else if ([scanner scanString:@")" intoString:NULL]) {
    16. bracketLevel--;
    17. }
    18. NSString* chunk;
    19. if ([scanner scanUpToString:@"+" intoString:&chunk]) {
    20. if (bracketLevel == 0) {
    21. [row appendFormat:@"\r\n%@", chunk];
    22. }
    23. else {
    24. [row appendString:chunk];
    25. }
    26. }
    27. if (row) {
    28. [rows addObject:row];
    29. }
    30. }
    31. NSLog(@"Zeilen:%@", rows);
    32. return rows;
    33. }
    Alles anzeigen


    Funktioniert nur für Maßketten ohne Klammern und ohne "+"..

    Was mache ich bloß falsch, dass ich nicht den richtigen Ansatz finde bzw. ihn realisiert bekomme? :(
    Man kann alles schaffen. Man muss es nur wollen ;)
    www.regetskcob.github.io
  • gritsch schrieb:

    du machst ja auch was relativ sinnfreies!


    Ja! -.- Aber ich finde einfach keinen richtigen Weg...

    gritsch schrieb:

    du sollst bis zu +() scannen und dann auswerten.


    Habe nun noch mal alles auf Anfang gesetzt:

    Quellcode

    1. + (NSArray *)GetMasskettenZeilenGetrennt:(NSString *)masskette
    2. {
    3. NSMutableArray *rows = [NSMutableArray new];
    4. int bracketLevel = -1;
    5. masskette = [masskette stringByReplacingOccurrencesOfString:@"\r\n" withString:@""];
    6. NSScanner *scanner = [NSScanner scannerWithString:masskette];
    7. NSCharacterSet *klammerPlusSet = [NSCharacterSet characterSetWithCharactersInString:@"()+"];
    8. while (![scanner isAtEnd]) {
    9. NSMutableString *row = [NSMutableString new];
    10. NSString* chunk;
    11. if ([scanner scanUpToCharactersFromSet:klammerPlusSet intoString:&chunk]) {
    12. [row appendString:chunk];
    13. }
    14. if (row) {
    15. [rows addObject:row];
    16. }
    17. }
    18. return rows;
    19. }
    Alles anzeigen


    Das wäre ja nun das Scannen bis zu einem der Zeichen, oder nicht? Wie würde man jetzt die Auswertung beifügen?

    PS: Das klappt für Maßketten ohne diese zeichen nun noch, sobald aber Klammern bspw. enthalten sind bin ich in einer art Endlosschleife.
    Man kann alles schaffen. Man muss es nur wollen ;)
    www.regetskcob.github.io
  • DanielBocksteger95 schrieb:

    Ja genau, daher war meine Frage ja nun, wie die Auswertung zu realisieren wäre.

    Wie kann ich auf den aktuellen Punkt sozusagen zugreifen und gucken wo ich nun bin?


    du kannst dafür scanString verwenden oder eben abprüfen ob du nicht am ende bist und falls nicht dann die scanlocation auslesen und anhand von characteratindex das zeichen aus dem originalstring fischen...
  • Etwa so?

    Quellcode

    1. while (![scanner isAtEnd]) {
    2. NSMutableString *row = [NSMutableString new];
    3. NSString* chunk;
    4. if ([scanner scanUpToCharactersFromSet:klammerPlusSet intoString:&chunk]) {
    5. if ([scanner scanLocation] < [masskette length]) {
    6. NSString *character = [masskette stringAtIndex:[scanner scanLocation]];
    7. if ([character isEqualToString:@"("]) {
    8. bracketLevel++;
    9. }
    10. else if ([character isEqualToString:@")"]) {
    11. bracketLevel--;
    12. }
    13. else if ([character isEqualToString:@"+"]) {
    14. if (bracketLevel < 0 || bracketLevel > 0) {
    15. [row appendString:chunk];
    16. }
    17. else {
    18. [row appendFormat:@"\r\n%@", chunk];
    19. }
    20. }
    21. }
    22. }
    23. NSLog(@"Zeile:%@", row);
    24. if (row) {
    25. [rows addObject:row];
    26. }
    27. }
    28. return rows;
    Alles anzeigen


    Ist allerdings weiterhin so, dass es sich bei Maßketten mit ( oder ) in einer Endlosschleife verfängt...
    Man kann alles schaffen. Man muss es nur wollen ;)
    www.regetskcob.github.io

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von DBocksteger ()

  • Die Logik von NSScanner erschliesst sich mir teilweise auch nicht so recht. Der scannt teilweise die wildesten Sachen.

    Ich würde es auch wie Claus direkt Old-School lösen. Dies sollte dann etwa so aussehen:

    Quellcode

    1. ​NSMutableString *result = [NSMutableString string];
    2. int bracketLevel = 0;
    3. int i = 0;
    4. while (i < masskette.length)
    5. {
    6. NSString *nextChar = [masskette substringWithRange:NSMakeRange(i, 1)];
    7. if ([@"(" isEqualToString:nextChar])
    8. bracketLevel++;
    9. else if ([@")" isEqualToString:nextChar])
    10. bracketLevel--;
    11. else if ([@"+" isEqualToString:nextChar] && bracketLevel == 0)
    12. [result appendString:@"\n"];
    13. [result appendString:nextChar];
    14. i++;
    15. }
    16. NSLog(@"result:%@",result);
    Alles anzeigen
  • MCDan schrieb:

    Die Logik von NSScanner erschliesst sich mir teilweise auch nicht so recht. Der scannt teilweise die wildesten Sachen.

    Ich würde es auch wie Claus direkt Old-School lösen. Dies sollte dann etwa so aussehen:

    Quellcode

    1. ​NSMutableString *result = [NSMutableString string];
    2. int bracketLevel = 0;
    3. int i = 0;
    4. while (i < masskette.length)
    5. {
    6. NSString *nextChar = [masskette substringWithRange:NSMakeRange(i, 1)];
    7. if ([@"(" isEqualToString:nextChar])
    8. bracketLevel++;
    9. else if ([@")" isEqualToString:nextChar])
    10. bracketLevel--;
    11. else if ([@"+" isEqualToString:nextChar] && bracketLevel == 0)
    12. [result appendString:@"\n"];
    13. [result appendString:nextChar];
    14. i++;
    15. }
    16. NSLog(@"result:%@",result);
    Alles anzeigen


    und warum "substringWithRange" und nicht "characterAtIndex"?
    ersteres ist ja komplizierter (zu schreiben und zu lesen) und auch noch langsamer ;)