2016-07-22 7 views
0

In Ruby, was ist der einfachste Weg, eine Zeichenfolge in der folgenden Weise zu teilen?Ruby split string und preserve separator

  • 'abc+def' sollte ['abc', '+', 'def']

  • 'abc\*def+eee' aufzuspalten zu ['abc', '\*', 'def', '+', 'eee']

  • 'ab/cd*de+df' sollte ['ab', '/', 'cd', '\*', 'de', '+', 'df']

Die Idee, die Zeichenfolge über diese Symbole zu teilen ist aufgeteilt aufgeteilt werden soll: ['-', '+', '*', '/'] und speichern Sie diese Symbole auch im Ergebnis an geeigneten Stellen.

+0

Hinweis: '.split' akzeptiert reguläre Ausdrücke –

+0

Willkommen bei Stack Overflow. Bitte lesen Sie "[fragen]" und die verlinkten Seiten. Wir müssen Beweise für Ihre Bemühungen zur Lösung des Problems sehen. Hast du Code geschrieben? Wenn nein, warum nicht? Wo haben Sie nach einer Lösung gesucht? Wenn du nicht gesucht hast, warum? Momentan scheint Ihre Frage ein Plädoyer für uns zu sein, den Code für Sie zu schreiben, für den SO nicht zuständig ist. –

+0

@theTinMan Sorry, darüber. Das werde ich bei künftigen Fragen berücksichtigen. – Lokesh

Antwort

10

Option 1

/\b/ ist ein word boundary und hat Null-Breite, so dass es keine Zeichen verbrauchen

'abc+def'.split(/\b/) 
# => ["abc", "+", "def"] 

'abc*def+eee'.split(/\b/) 
# => ["abc", "*", "def", "+", "eee"] 

'ab/cd*de+df'.split(/\b/) 
# => ["ab", "/", "cd", "*", "de", "+", "df"] 

Option 2

Wenn Ihr string enthält andere Wortbegrenzungszeichen und Sie möchten nur t o Teilen auf -, +, * und /, dann können Sie capture groups verwenden. Wenn eine Erfassungsgruppe verwendet wird, enthält String#split auch erfasste Zeichenketten im Ergebnis. (Danke für den Hinweis @Jordan) (@Cary Swoveland leid, ich habe nicht gesehen, Ihre Antwort, wenn ich diese bearbeitet)

'abc+def'.split /([+*\/-])/ 
# => ["abc", "+", "def"] 

'abc*def+eee'.split /([+*\/-])/ 
# => ["abc", "*", "def", "+", "eee"] 

'ab/cd*de+df'.split /([+*\/-])/ 
# => ["ab", "/", "cd", "*", "de", "+", "df"] 

Option 3

Schließlich, für diejenigen mit einer Sprache, Die Unterstützung für das Teilen von Strings mit einer Erfassungsgruppe kann nicht unterstützt werden. Sie können zwei lookarounds verwenden. Lookarounds sind auch Null-Breite Streichhölzer, so dass sie keine Zeichen verbrauchen

'abc+def'.split /(?=[+*\/-])|(?<=[+*\/-])/ 
# => ["abc", "+", "def"] 

'abc*def+eee'.split /(?=[+*\/-])|(?<=[+*\/-])/ 
# => ["abc", "*", "def", "+", "eee"] 

'ab/cd*de+df'.split /(?=[+*\/-])|(?<=[+*\/-])/ 
# => ["ab", "/", "cd", "*", "de", "+", "df"] 

Die Idee hier ist auf jeden Charakter zu teilen, die von einem Ihrer Separatoren, oder ein beliebiges Zeichen vorangestellt ist, die von einer der gefolgt wird Trennzeichen. Lassen Sie uns visuelle

ab ⍿/⍿ cd ⍿ * ⍿ de ⍿ + ⍿ df

Die kleinen Symbole ein wenig tun, entweder vorangehen oder von einem der Separatoren gefolgt. Hier wird die Saite geschnitten.


Option 4

Vielleicht Ihre Sprache nicht über eine Zeichenfolge split Funktion oder sinnvolle Möglichkeiten, um mit regulären Ausdrücken zu interagieren. Es ist schön zu wissen, dass man nicht herumsitzen muss, um zu raten, ob es clevere eingebaute Verfahren gibt, die auf magische Weise deine Probleme lösen.Es gibt fast immer einen Weg, Ihr Problem mit einfachen Anweisungen zu lösen

class String 
    def head 
    self[0] 
    end 
    def tail 
    self[1..-1] 
    end 
    def reduce acc, &f 
    if empty? 
     acc 
    else 
     tail.reduce yield(acc, head), &f 
    end 
    end 
    def separate chars 
    res, acc = reduce [[], ''] do |(res, acc), char| 
     if chars.include? char 
     [res + [acc, char], ''] 
     else 
     [res, acc + char] 
     end 
    end 
    res + [acc]  
    end 
end 

'abc+def'.separate %w(- +/*) 
# => ["abc", "+", "def"] 

'abc*def+eee'.separate %w(- +/*) 
# => ["abc", "*", "def", "+", "eee"] 

'ab/cd*de+df'.separate %w(- +/*) 
# => ["ab", "/", "cd", "*", "de", "+", "df"] 
+0

Großartig! Vor allem die Blicke. Danke vielmals. Prost! – Lokesh

+0

Schöne Erklärung auch. – Lokesh

+0

Der Lookaround ist Overkill. 'String # split' behält Captures bei, also brauchen Sie nur' string.split/([+ * \/-])/'. –

2

Ich sehe dies auf einen Teil der Antwort @ naomic ist in der Nähe ist, aber ich werde es für die kleinen Unterschiede lassen.

splitters = ['-', '+', '*', '/'] 

r = /(#{ Regexp.union(splitters) })/ 
    # => /((?-mix:\-|\+|\*|\/))/ 

'abc+def'.split r 
    #=> ["abc", "+", "def"] 
"abc\*def+eee".split r 
    #=> ["abc", "*", "def", "+", "eee"] 
'ab/cd*de+df'.split r 
    #=> ["ab", "/", "cd", "*", "de", "+", "df"] 

Hinweise:

  • die regex Orte #{ Regexp.union(splitters) } in einer Capture-Gruppe, wodurch String#split die Saiten enthalten, die die Spaltung (letzter Satz des dritten Absatzes) tun.
  • Die zweite Beispielzeichenfolge muss in doppelte Anführungszeichen gesetzt werden, um * zu umgehen.
+0

Nice Verwendung von "Regexp.union". Froh, dass ich gelernt habe, dass "String # Split" die Verwendung von Capture-Gruppen erlaubt. Das habe ich vorher nie gewusst^_ ^ – naomik