/ / Split-Zeichen Vektor bei Mathe-Vergleiche Zeichen in R - r, Regex

Aufgeteilter Charaktervektor bei Mathevergleichen unterzeichnet herein R - r, Regex

Ich möchte den Ausdruck durch mathematische Vergleiche z.

unlist(strsplit("var<3", "(?=[=<>])", perl = TRUE))
unlist(strsplit("var==5", "(?=[=<>])", perl = TRUE))
unlist(strsplit("var>2", "(?=[=<>])", perl = TRUE))

Die Ergebnisse sind:

[1] "var" "<"   "3"
[1] "var" "="   "="   "5"
[1] "var" ">"   "2"

Für das zweite Beispiel oben würde ich gerne bekommen [1] "var" "==" "5"so die beiden = sollte als einzelnes Element zurückgegeben werden. Wie muss ich meinen regulären Ausdruck ändern, um dies zu erreichen? (Ich habe bereits versucht Gruppierung und Quantifizierer für "==", aber nichts hat funktioniert - reguläre Ausdrücke sind nicht meine Freunde ...)

Antworten:

9 für die Antwort № 1

Sie können eine PCRE-Regex verwenden Spiel die benötigten Teilstrings:

==|[<>]|(?:(?!==)[^<>])+

Auch zu unterstützen !=, modifiziere es als

[!=]=|[<>]|(?:(?![=!]=)[^<>])+

Siehe die Regex-Demo.

Einzelheiten:

  • == - 2 = Zeichen
  • | - oder
  • [<>] - ein < oder >
  • | - oder
  • (?:(?!==)[^<>])+ - 1 oder mehr Zeichen außer < und > ([^<>]) die nicht beginnen a == Char-Sequenz (a temperiertes gieriges Token).

HINWEIS: Dies ist leicht erweiterbar durch Hinzufügen von mehr Alternativen und Anpassung der temperierten gierigen Token.

R-Test:

> text <- "Text1==text2<text3><More here"
> res <- regmatches(text, gregexpr("==|[<>]|(?:(?!==)[^<>])+", text, perl=TRUE))
> res
[[1]]
[1] "Text1"     "=="        "text2"     "<"         "text3"     ">"
[7] "<"         "More here"

6 für die Antwort № 2

Erweitern von meiner Idee in Kommentaren, nur für die Formatierung:

tests=c("var==5","var<3","var.name>5")
regmatches(tests,regexec("([a-zA-Z0-9_.]+)(\W+)([a-zA-Z0-9_.]+)",tests))

w ist [a-zA-Z0-9_] und W es ist das Gegenteil [^a-zA-Z0-9_]Ich habe es nach dem Kommentar erweitert. in der Zeichenklasse, und wie R nicht unterstützt w in der Zeichenklasse in der Basisregex (müssen Perl verwenden = TRUE).

Also die Regex Suche für mindestens 1 von w und., Dann mindestens 1 nicht in w (um Operatoren zu entsprechen) und dann mindestens 1 von w und Punkt.

Jeder Schritt wird erfasst und dies ergibt:

[[1]]
[1] "var==5" "var"    "=="     "5"

[[2]]
[1] "var<3" "var"   "<"     "3"

[[3]]
[1] "var.name>5" "var.name"   ">"          "5"

du kannst hinzufügen * zwischen den einzelnen Erfassungsgruppen, wenn Ihre Einträge Platz um den Operator haben könnten, wenn sie nicht vom Operator erfasst werden.


5 für die Antwort № 3

Mit Worten "Grenzen (\b) und 2 Möglichkeiten für den Lookaround angeben:

unlist(strsplit("var==5", "(?=(\b[^a-zA-Z0-9])|(\b[a-zA-Z0-9]\b))", perl = TRUE))
[1] "var" "=="  "5"

unlist(strsplit("var<3", "(?=(\b[^a-zA-Z0-9])|(\b[a-zA-Z0-9]\b))", perl = TRUE))
[1] "var" "<"   "3"
unlist(strsplit("var>2", "(?=(\b[^a-zA-Z0-9])|(\b[a-zA-Z0-9]\b))", perl = TRUE))
[1] "var" ">"   "2"

Erläuterung:

Split am Ende des "Wortes" und danach gibt es entweder ein nicht-alphanumerisches Zeichen \b[^a-zA-Z0-9] oder es ist das Ende des "Wortes" und danach gibt es ein alphanumerisches Zeichen.

BEARBEITEN:

Tatsächlich würde der obige Code unerwartete Ergebnisse haben, wenn die Zahl am Ende 10 oder mehr ist.
Eine andere Option ist zu verwenden lookbehind und teilen, wenn vorher ein Nicht-Alphanum-Zeichen, gefolgt von einer Wortkante, oder ein Alphanum-Zeichen, gefolgt von einer Wortkante, vorliegt:

strsplit("var<20", "(?<=(([^a-zA-Z0-9]\b)|([a-zA-Z0-9]\b)))", perl = TRUE)[[1]]
#[1] "var" "<"   "20"
strsplit("var==20", "(?<=(([^a-zA-Z0-9]\b)|([a-zA-Z0-9]\b)))", perl = TRUE)[[1]]
#[1] "var" "=="  "20"
strsplit("var!=5", "(?<=(([^a-zA-Z0-9]\b)|([a-zA-Z0-9]\b)))", perl = TRUE)[[1]]
#[1] "var" "!="  "5"

EDIT2:

Totally stehlen @ Tensibai Weg, um alphanum (+ Unterstrich) / non alphanum Zeichen, die oben genannten zu definieren regex kann vereinfachen zu: "(?<=((\W\b)|(\w\b)))"