Test of tekens in een tekenreeks staan

Ik probeer te bepalen of een tekenreeks een subset is van een andere tekenreeks. Bijvoorbeeld:

chars <- "test"
value <- "es"

Ik wil TRUE retourneren als “value” wordt weergegeven als onderdeel van de tekenreeks “chars”. In het volgende scenario zou ik false willen retourneren:

chars <- "test"
value <- "et"

Antwoord 1, autoriteit 100%

Gebruik de functie grepl

grepl( needle, haystack, fixed = TRUE)

vind ik leuk:

grepl(value, chars, fixed = TRUE)
# TRUE

Gebruik ?greplvoor meer informatie.


Antwoord 2, autoriteit 42%

Antwoord

Zucht, het kostte me 45 minuten om het antwoord op deze simpele vraag te vinden. Het antwoord is: grepl(needle, haystack, fixed=TRUE)

# Correct
> grepl("1+2", "1+2", fixed=TRUE)
[1] TRUE
> grepl("1+2", "123+456", fixed=TRUE)
[1] FALSE
# Incorrect
> grepl("1+2", "1+2")
[1] FALSE
> grepl("1+2", "123+456")
[1] TRUE

Interpretatie

grepis genoemd naar het uitvoerbare bestand van Linux, dat zelf een acroniem is van “Global Regular Expression Print”, zou het invoerregels lezen en deze vervolgens afdrukken als ze overeenkwamen met de argumenten die u gaf. “Globaal” betekende dat de overeenkomst overal op de invoerregel kon voorkomen, ik zal “Regular Expression” hieronder uitleggen, maar het idee is dat het een slimmere manier is om de string te matchen (R noemt dit “karakter”, bijv. class("abc")), en “Afdrukken” omdat het een opdrachtregelprogramma is, betekent het verzenden van uitvoer dat het naar de uitvoertekenreeks wordt afgedrukt.

Het programma grepis in feite een filter, van invoerregels tot uitvoerregels. En het lijkt erop dat de grep-functie van R op dezelfde manier een reeks invoer nodig heeft. Om mij volkomen onbekende redenen (ik begon pas ongeveer een uur geleden met R te spelen), retourneert het een vector van de indexen die overeenkomen, in plaats van een lijst met overeenkomsten.

Maar terug naar uw oorspronkelijke vraag, wat we echt willen, is weten of we de speld in de hooiberg hebben gevonden, een waar/onwaar waarde. Ze hebben blijkbaar besloten om deze functie greplte noemen, zoals in “grep” maar met een “Llogische” retourwaarde (ze noemen true en false logische waarden, bijv. class(TRUE)).

Dus nu weten we waar de naam vandaan komt en wat hij moet doen. Laten we teruggaan naar reguliere expressies. De argumenten, ook al zijn het strings, worden gebruikt om reguliere expressies te bouwen (hierna: regex). Een regex is een manier om een string te matchen (als deze definitie je irriteert, laat het dan los). De regex akomt bijvoorbeeld overeen met het teken "a", de regex a*komt overeen met het teken "a"0 of meer keer, en de regex a+komt 1 of meer keer overeen met het teken "a". Vandaar dat in het bovenstaande voorbeeld de naald die we zoeken 1+2, wanneer behandeld als een regex, betekent “een of meer 1 gevolgd door een 2″… maar de onze wordt gevolgd door een plus !

1 +2 als regex

Dus, als je de greplgebruikte zonder fixedin te stellen, zouden je naalden per ongeluk hooibergen zijn, en dat zou per ongeluk heel vaak werken, we kunnen zien dat het zelfs werkt voor het voorbeeld van de OP. Maar dat is een latente bug! We moeten het vertellen dat de invoer een string is, geen regex, wat blijkbaar is waar fixedvoor is. Waarom vast? Geen idee, maak een bladwijzer voor dit antwoord, want je zult het waarschijnlijk nog 5 keer moeten opzoeken voordat je het uit je hoofd kunt leren.

Een paar laatste gedachten

Hoe beter uw code is, hoe minder geschiedenis u hoeft te kennen om er iets van te begrijpen. Elk argument kan minstens twee interessante waarden hebben (anders zou het geen argument hoeven te zijn), de documenten geven hier 9 argumenten weer, wat betekent dat er minstens 2^9=512 manieren zijn om het aan te roepen, dat is veel werk om schrijf, test en onthoud … ontkoppel dergelijke functies (splits ze op, verwijder afhankelijkheden van elkaar, string dingen zijn anders dan regex dingen zijn anders dan vector dingen). Sommige opties sluiten elkaar ook uit, geven gebruikers geen verkeerde manieren om de code te gebruiken, dwz de problematische aanroep moet structureel onzinnig zijn (zoals het doorgeven van een optie die niet bestaat), niet logisch onzinnig (waar je moet een waarschuwing uitzenden om het uit te leggen). Metaforisch gesteld: de voordeur in de zijkant van de 10e verdieping vervangen door een muur is beter dan een bord op te hangen dat waarschuwt tegen het gebruik ervan, maar het is beter dan geen van beide. In een interface definieert de functie hoe de argumenten eruit moeten zien, niet de aanroeper (omdat de aanroeper afhankelijk is van de functie, en alles afleidt waarmee iedereen het ooit zou willen aanroepen, maakt de functie ook afhankelijk van de aanroepers, en dit type van cyclische afhankelijkheid zal een systeem snel verstoppen en nooit de voordelen opleveren die u verwacht). Wees erg op uw hoede voor dubbelzinnige typen, het is een ontwerpfout dat dingen als TRUEen 0en "abc"allemaal vectoren zijn.


Antwoord 3, autoriteit 7%

U wilt grepl:

> chars <- "test"
> value <- "es"
> grepl(value, chars)
[1] TRUE
> chars <- "test"
> value <- "et"
> grepl(value, chars)
[1] FALSE

Antwoord 4, autoriteit 7%

Gebruik deze functie uit het stringipakket:

> stri_detect_fixed("test",c("et","es"))
[1] FALSE  TRUE

Enkele benchmarks:

library(stringi)
set.seed(123L)
value <- stri_rand_strings(10000, ceiling(runif(10000, 1, 100))) # 10000 random ASCII strings
head(value)
chars <- "es"
library(microbenchmark)
microbenchmark(
   grepl(chars, value),
   grepl(chars, value, fixed=TRUE),
   grepl(chars, value, perl=TRUE),
   stri_detect_fixed(value, chars),
   stri_detect_regex(value, chars)
)
## Unit: milliseconds
##                               expr       min        lq    median        uq       max neval
##                grepl(chars, value) 13.682876 13.943184 14.057991 14.295423 15.443530   100
##  grepl(chars, value, fixed = TRUE)  5.071617  5.110779  5.281498  5.523421 45.243791   100
##   grepl(chars, value, perl = TRUE)  1.835558  1.873280  1.956974  2.259203  3.506741   100
##    stri_detect_fixed(value, chars)  1.191403  1.233287  1.309720  1.510677  2.821284   100
##    stri_detect_regex(value, chars)  6.043537  6.154198  6.273506  6.447714  7.884380   100

Antwoord 5, autoriteit 6%

Kan ook gedaan worden met behulp van de “stringr” bibliotheek:

> library(stringr)
> chars <- "test"
> value <- "es"
> str_detect(chars, value)
[1] TRUE
### For multiple value case:
> value <- c("es", "l", "est", "a", "test")
> str_detect(chars, value)
[1]  TRUE FALSE  TRUE FALSE  TRUE

Antwoord 6, autoriteit 5%

Voor het geval u ook wilt controleren of een tekenreeks (of een reeks tekenreeksen) meerdere subtekenreeksen bevat(ten), kunt u ook de ‘|’ gebruiken tussen twee substrings.

>substring="as|at"
>string_vector=c("ass","ear","eye","heat") 
>grepl(substring,string_vector)

Je krijgt

[1]  TRUE FALSE FALSE  TRUE

aangezien het eerste woord een substring “as” heeft en het laatste woord een substring “at”


Antwoord 7, autoriteit 2%

Gebruik grepof greplmaar let op of je reguliere expressies wilt gebruiken.

Standaard gebruiken grepen gerelateerd een reguliere expressieom overeen te komen, geen letterlijke subtekenreeks. Als je dat niet verwacht en je probeert te matchen op een ongeldige regex, werkt het niet:

> grep("[", "abc[")
Error in grep("[", "abc[") : 
  invalid regular expression '[', reason 'Missing ']''

Gebruik fixed = TRUEom een echte substringtest uit te voeren.

> grep("[", "abc[", fixed = TRUE)
[1] 1

Als je regex wilt, prima, maar dat is niet wat de OP lijkt te vragen.


Antwoord 8, autoriteit 2%

U kunt grep

. gebruiken

grep("es", "Test")
[1] 1
grep("et", "Test")
integer(0)

Antwoord 9

Soortgelijk probleem hier: op basis van een string en een lijst met trefwoorden, detecteer welke van de trefwoorden in de string voorkomen, indien aanwezig.

Aanbevelingen uit deze thread suggereren stringr‘s str_detecten grepl. Dit zijn de benchmarks uit het microbenchmarkpakket:

Gebruik

map_keywords = c("once", "twice", "few")
t = "yes but only a few times"
mapper1 <- function (x) {
  r = str_detect(x, map_keywords)
}
mapper2 <- function (x) {
  r = sapply(map_keywords, function (k) grepl(k, x, fixed = T))
}

en dan

microbenchmark(mapper1(t), mapper2(t), times = 5000)

we vinden

Unit: microseconds
       expr    min     lq     mean  median      uq      max neval
 mapper1(t) 26.401 27.988 31.32951 28.8430 29.5225 2091.476  5000
 mapper2(t) 19.289 20.767 24.94484 23.7725 24.6220 1011.837  5000

Zoals je kunt zien, meer dan 5.000 herhalingen van het zoeken op trefwoord met behulp van str_detecten greplover een praktische reeks en vector van trefwoorden, greplpresteert een stuk beter dan str_detect.

Het resultaat is de booleaanse vector rdie aangeeft welke van de zoekwoorden in de tekenreeks voorkomen, indien aanwezig.

Daarom raad ik aan om greplte gebruiken om te bepalen of er zoekwoorden in een string voorkomen.

Other episodes