2016-07-31 5 views
2

Ich versuche, ein Stück Code zu schreiben, der das erste und letzte Zeichen aus einer Zeichenfolge entfernt. Die Zeichen müssen durch Leerzeichen und nicht durch Kommas getrennt sein. z.B. ("1, 2, 3, 4") würde zu ("2 3") geändert werden.NULL zurückgeben, nachdem Zeichenfolge in Ruby leer gemacht wird

Das Bit, auf dem ich feststecke, ist - wenn ich die ersten und letzten Zeichen entferne und die Zeichenfolge jetzt leer ist, sollte es z. ("1, 2") wäre nil.

Bisher habe ich:

def array(string) 
if string == "" 
    return nil 
else 
    string.gsub!(',',' ') 
    string.split 
    string[2..-3] 
end 
end 

Könnte jemand erklären, wo ich falsch gehe?

Antwort

3

Hier ist eine feste Version des Codes:

def array(string) 
    string.gsub!(',',' ') 
    split = string.split 
    trimmed = split[1..-2].join(' ') 
    if trimmed == "" 
    return nil 
    else 
    return trimmed 
    end 
end 

p array('1, 2, 3, 4') # "2 3" 
p array('2, 3') # nil 

Ein paar Probleme mit dem Code:

  1. Sie wurden Ihrer Funktion am Start für einen leeren String Überprüfung statt nach Du hast es getrimmt. (So ​​würde es nur nil zurückgeben, wenn Sie genau "" übergeben.)
  2. Sie speicherten nicht die Ergebnisse der Sachen, die Sie taten. string.split ändert nicht den Wert string. Es gibt ein Array zurück, das das Ergebnis der Teilung der Zeichenfolge ist. Also müssen Sie das Ergebnis in einem Array speichern. (Z. B. split = string.split.) string.gsub!(...) ist anders. Das Ausrufezeichen bedeutet, dass es sich um eine destruktive Operation handelt. Es ändert tatsächlich die Zeichenfolge.
  3. Ihre Indizes waren falsch bei der endgültigen Trimmung, aber das liegt wahrscheinlich daran, dass die Aufteilung nicht funktionierte, also haben Sie versucht, die Indizes anzupassen.
  4. Sie haben die Ergebnisse nie wieder mit Leerzeichen verknüpft.

Hier ist eine andere Version für Sie versuchen:

def trim(string) 
    trimmed = string.split(', ')[1..-2].join(' ') 
    trimmed.empty? ? nil : trimmed 
end 

EDIT

Es ist einfach fiel mir ein, dass vielleicht waren die Indizes nach rechts und Sie nicht die Absicht hatte eigentlich gar aufzuspalten ... hier ist eine andere funktionierende Version des Codes:

def array(string) 
    string.gsub!(',', '') # NOTE: '' rather than ' ' 
    trimmed = string[2..-3] 
    if trimmed == "" 
    return nil 
    else 
    return trimmed 
    end 
end 

Beachten Sie, dass dies ver Die Setzung des Codes beruht darauf, dass die durch Komma getrennten Werte genau ein Zeichen lang sind. Es wird nicht funktionieren, wenn Sie '12, 35, 421' übergeben. Ich würde aus diesem Grund einen Ansatz basierend auf split halten.

+0

Vielen Dank das ist toll, vor allem für die Erklärung der Probleme mit meinem Code! Wirklich hilft mir, es auch besser zu verstehen. – loopylou

0

Ich würde einen regulären Ausdruck in Kombination mit den Methoden String#count, String#[] und String#tr verwenden.

R =/
    \A   # match start of string 
    .+?,\s+  # match >= 1 characters lazily (`?`) follow by a comma and >= 1 spaces 
    \K   # forget everything matched so far 
    .+   # match >= 1 characters greedily 
    (?=,\s+\S+\z) # match a comma, >= 1 spaces, >= 1 characters other than 
        # sapces and end of string in a positive lookahead 
    /x   # free-spacing regex definition mode 

def doit(str) 
    str.count(',') <= 1 ? nil : str[R].tr(',', ' ') 
end 

doit "11, 12, 13, 14" 
    #=> "12 13" 

doit "1, 4" 
    #=> nil 

doit "1" 
    #=> nil 

doit "" 
    #=> nil 

Die Schritte sind wie folgt.

str = "11, 12, 13, 14" 
str.count(',') <= 1 
    #=> false 
s = str[R] 
    #=> "12, 13" 
s.tr(',', ' ') 
    #=> "12 13" 

str = "1, 4" 
str.count(',') <= 1 
    #=> true 
nil 

Dieser reguläre Ausdruck würde konventionell

/\A.+?,\s+\K.+(?=,\s+\S+\z)/ 

Sie alternativ eine Aufnahme geschrieben werden Gruppe in der Regex anstelle der beiden lookarounds verwenden:

R =/
    \A  # match start of string 
    .+?,\s+ # match >= 1 characters lazily (`?`), a comma and >= 1 spaces 
    (.+) # match one or more characters (greedily) in capture group 1 
    ,\s+\S+ # match a comma, >= 1 spaces, >= 1 characters other than spaces 
    \z  # match end of string 
    /x  # free-spacing regex definition mode 

und dann

def doit(str) 
    str.count(',') <= 1 ? nil : str[R,1].tr(',', ' ') 
end 

Die Auswahl ist allgemein verfügbar. Ich bevorzuge Lookarounds oder \K, aber es ist eine persönliche Vorliebe.

+0

Ruh roh. Obwohl es schlau ist, ist es ein wenig schwer zu lesen. Ich müsste jedes Mal darüber nachdenken, wenn ich im Quellcode darauf stoße. :-) –

+0

@JIm, ein paar Punkte: 1) Die Frage schrie "regulären Ausdruck". 2) Mit der Praxis werden Regex-Konstrukte wie positive Lookbehinds und Lookaheads sehr natürlich und sofort verstanden. Sobald Sie wissen, was 'str [R]' zurückgibt, ist der Rest offensichtlich. 3) Wenn Sie über die Lösung nachdenken müssen, ist das notwendigerweise eine schlechte Sache? Schließlich bedeutet das, dass Sie etwas lernen, das es in Zukunft leichter machen sollte, diese und andere Regexes zu verstehen, und Ihnen hilft, Regexes in Ihrem eigenen Code zu nutzen. –

+0

Dieser Code hat einen Syntaxfehler (fehlt links paren, glaube ich), es gibt Strings wie '" 2 3 "' (zwei Leerzeichen) zurück, und es gibt nicht "nil" zurück, wie die ursprüngliche Frage gestellt. Und obwohl es ein interessanter Ansatz ist, ist es definitiv nicht etwas, das ich einem Anfänger empfehlen würde, sogar zu lesen, geschweige denn zu benutzen. – smarx

0
def doit(str) 
    return nil if str.count(',') <= 1 
    str[(str.index(',')+1)...str.rindex(',')].lstrip.tr(',', ' ') 
end 

String#rindex ist verwenden Sie den Index des letzten Komma in der Zeichenfolge zu finden. Der Bereich ist mit drei Punkten definiert, um das letzte Komma auszuschließen.

doit "1, 2, 3, 4" #=> "2 3" 
doit "11, 12, 13" #=> "12" 
doit "1, 4"  #=> nil 
doit "1"   #=> nil 
doit ""   #=> nil 
+0

Lol - wenn es diese Syntax kommt, bevorzuge ich die Single-Line Regex Ihrer anderen Antwort. –

Verwandte Themen