2016-08-03 14 views
0

Ich versuche, ein Ruby-Skript zu schreiben, das alle Rem-Werte in einer CSS-Datei durch ihre px-Entsprechungen ersetzt.Wie reguliere ich eine unbekannte Anzahl von sich wiederholenden Elementen?

body{font-size:1.6rem;margin:4rem 7rem;} 

Der Match Ich mag würde zu bekommen wäre: Dies wäre ein Beispiel CSS-Datei

# Match 1   Match 2 
# 1. font-size  1. margin 
# 2. 1.6   2. 4 
#      3. 7 

aber ich völlig ahnungslos bin, wie mehrere und unterschiedliche Match Ergebnisse zu erhalten. Die RegEx, die mich bekam am nächsten ist dies (you can also take a look at it at Rubular):

/([^}{;]+):\s*([0-9.]+?)rem(?=\s*;|\s*})/i 

Dies wird einzelne Instanzen Wert Erklärungen entsprechen (so wird es das gewünschte Spiel 1 Ergebnis richtig zurück), aber völlig außer Acht lässt Multiples.

Ich habe auch etwas nach dem Vorbild von ([0-9.]+?rem\s*)+ versucht, aber das hat nicht das gewünschte Ergebnis zurückgegeben, und ich habe nicht das Gefühl, dass ich auf dem richtigen Weg bin, da es nicht mehrere Ergebnisdatensätze zurückgibt.


EDIT Nach den Vorschlägen in den Antworten, endete ich das Problem, wie diese Lösung bis:

# search for any declarations that contain rem unit values and modify blockwise 
@output.gsub!(/([^ }{;]+):\s*([^}{;]*[0-9.]rem+[^;]*)(?=\s*;|\s*})/i) do |match| 
    # search for any single rem value 
    string = match.gsub(/([0-9.]+)rem/i) do |value| 
    # convert the rem value to px by multiplying by 10 (this is not universal!) 
    value = sprintf('%g', Regexp.last_match[1].to_f * 10).to_s + 'px' 
    end 
    string += ';' + match # append the original match result to the replacement 
    match = string # overwrite the matched result 
end 
+0

Versuch '(\ s * [\ w- ] *:)? ([\ d.] *) rem/g' –

+0

@MartinDabbelJuSmelter: Ruby hat keine globale 'g' Option. – TheThirdMan

Antwort

1

Sie können keine dynamische Anzahl von Match-Gruppen erfassen (zumindest nicht in Ruby).

Stattdessen könnten Sie entweder eine der folgenden Aktionen ausführen:

  1. Aufnahme den gesamten Wert und Split auf Platz
  2. Verwendung Multi-Level-Matching zuerst den gesamten Schlüssel/Wert-Paar zu erfassen und zum anderen mit dem Wert übereinstimmen. Sie können Blöcke mit der Methode match in Ruby verwenden.
+0

Der zweite Vorschlag ist großartig - indem man den String blockweise ändert, braucht man nichts von dem String zu nehmen, um mit der Trennung zu verfahren (da Sie nicht nur Leerzeichen, sondern auch Klammern und andere Zeichen trennen müssen, * dann * suchen Sie nach Vorkommen von rem). Danke für das Aufräumen! Ich fügte hinzu, wie ich mein Problem mit dem ersten Beitrag gelöst habe. – TheThirdMan

0

Diese Regex den Auftrag für Ihr Beispiel tun:

([^}{;]+):(?:([0-9\.]+?)rem\s?)?(?:([0-9\.]+?)rem\s?) 

Aber mit dem können Sie nichts wie vergleichen: margin:4rem 7rem 9rem

+0

Während dies bisher der einzige Weg ist, den ich auf 4 Eigenschaften erweitert habe (was ich am ehesten von CSS erwarten kann), habe ich mich gefragt, ob es möglich ist, eine unbekannte Anzahl von Elementen zu finden. Ihre Antwort erzeugt leider auch ein leeres zweites Ergebnis für das erste Spiel, was zu einer ziemlich unnötigen Nachbearbeitung führen würde; siehe [Rubular] (http://rubular.com/r/rL1x3VQNmp) – TheThirdMan

+1

Sie können keine unbekannte Menge an Element zuordnen, lesen Sie dies zur Erklärung: http://stackoverflow.com/questions/464736/python-regular- expressions-how-to-capture-multiple-groups-from-a-wildcard-expr # 464755 – baddger964

0

Dies ist, was ich habe in der Lage zu tun: DEMO

Regex: (?<={|;)([^:}]+)(?::)([^A-Za-z]+)

Und das ist, was wie mein Ergebnis aussieht:

# Match 1   Match 2 
# 1. font-size  1. margin 
# 2. 1.6   2. 4 

Wie @koffeinfrei sagt, dynamische Erfassung ist in Ruby nicht möglich. Wäre schlauer, die ganze Zeichenfolge zu erfassen und Leerzeichen zu entfernen.

0
str = 'body{font-size:1.6rem;margin:4rem 7rem;}' 
str.scan(/(?<=[{; ]).+?(?=[;}])/) 
    .map { |e| e.match /(?<prop>.+):(?<value>.+)/ } 
#⇒ [ 
# [0] #<MatchData "font-size:1.6rem" prop:"font-size" value:"1.6rem">, 
# [1] #<MatchData "margin:4rem 7rem" prop:"margin" value:"4rem 7rem"> 
# ] 

Letztere match könnte leicht zurück angepasst werden, was Sie wollen, value.split(/\s+/) alle Werte zurück, \d+ statt .+ werden Ziffern entsprechen nur usw.

Verwandte Themen