sub
Srovnávání se vzorem a nahrazování
grep {base} | Dokumentace R v češtině |
Popis
grep
, grepl
, regexpr
, gregexpr
a regexec
srovnávají každý prvkek vektoru řetězců s argumentem pattern
: funkce se od sebe odlišují ruzným formátem a množstvím detailů ve výsledku.
sub
a gsub
provádí nahrazení první, respektive všech nalezených shod.
Použití
grep(pattern, x, ignore.case = FALSE, perl = FALSE, value = FALSE,
fixed = FALSE, useBytes = FALSE, invert = FALSE)
grepl(pattern, x, ignore.case = FALSE, perl = FALSE,
fixed = FALSE, useBytes = FALSE)
sub(pattern, replacement, x, ignore.case = FALSE, perl = FALSE,
fixed = FALSE, useBytes = FALSE)
gsub(pattern, replacement, x, ignore.case = FALSE, perl = FALSE,
fixed = FALSE, useBytes = FALSE)
regexpr(pattern, text, ignore.case = FALSE, perl = FALSE,
fixed = FALSE, useBytes = FALSE)
gregexpr(pattern, text, ignore.case = FALSE, perl = FALSE,
fixed = FALSE, useBytes = FALSE)
regexec(pattern, text, ignore.case = FALSE, perl = FALSE,
fixed = FALSE, useBytes = FALSE)
Argumenty
pattern |
řetězec znaků obsahující regulární výraz (nebo řetězec znaků pro |
x, text |
vektor řetězců, ve kterém jsou prováděna srovnání, nebo jiný objekt, který může být převeden funkcí |
ignore.case |
pokud je |
perl |
logický argument: mají být použity Perl-kompatibilný regulární výrazy? |
value |
vstahuje se k funkci |
fixed |
logický argument. Pokud je |
useBytes |
logický argument. Pokud je |
invert |
logický argument. Pokud je |
replacement |
náhrada při shodě se vzorem u funkce |
Detaily
Argumenty, které mají být řetězec znaků nebo vektor řetězců, jsou nejdříve převedeny, je-li to možné, na typ character.
Každá ze zmíněných funkcí může pracovat v jednom ze tří následujících módů:
-
fixed = TRUE
: vyhledává přesné shody. -
perl = TRUE
: používá regulární výrazy stylu Perl. -
fixed = FALSE, perl = FALSE
: používá POSIX 1003.2 rozšířené regulární výrazy (výchozí nastavení).
Pro více informací o různých typech regulárních výrazů navštivte regular expression.
Funkce sub
a gsub
se liší v tom, že sub
nahrazuje pouze první shodu s pattern
, kdežto gsub
nahrazuje všechny shody. Pokud replacement
obsahuje zpětné odkazy, které nejsou definovány v pattern
, je výsledek neurčitý (zpětné odkazy jsou ale nejčastěji brány jako ""
).
U regexpr
, gregexpr
a regexec
je chybou, pokud se pattern
rovná NA
, v ostatních případech je hodnota NA
povolena a, je-li použita, navrátí vektor shodnotami NA
pro každé srovnání.
Hlavním důvodem použití useBytes
je, aby se předešlo signalizaci chyb/varovných hlášení u neplatných vstupů a napravým shodám u multibajtových místních nastaveních. Pro funkci regexpr
to však mění interpretaci výstupu. Jakákoliv konverze na bajty je u vstupů s označeným kódováním zablokována. Je provedena pouze tam, kde má vstup oznčené kódování "bytes"
(viz Encoding
).
Ignorování velkých a malých písmen nedává v případě srovnávání bajtů v multibajtovém lokálním nastavení smyl. Měli bychom počítat s tím, že useBytes = TRUE
funguje pouze pro znaky ASCII.
regexpr
a gregexpr
s perl = TRUE
umožňuje pojmenované podvýrazy ('named capture') ve stylu Pythonu, nelze však uplatnit u vstupů typu dlouhých vektorů.
Varovné hlášení o neplatných vstupech pro akutuální místní nastavení může nastat až 5 krát.
Srovnávání non-ASCII znaků s ignorováním velkých a malých písmen u možnosti perl = TRUE
závisí na knihovně PCRE, která byla sestavena s pomocí ‘Unicode property support’: není tedy potřeba extrení knihovny.
Hodnota
grep(value = FALSE)
navrací vektor indexů prvků x
, které se shodovaly (nebo neshodovaly, pokud invert = TRUE
). Vektor je typu integer. V případě vstupu dlouhého vektoru je to vektor typu double.
grep(value = TRUE)
navrací vektor řetězců, který obsahuje prvky z x
(po převodu na typ character), u kterých nastala shoda se vzorem (jsou zachovány názvy, nikoliv ostatní vlastnosti).
grepl
navrací vektor typu logical (zda se jednotlivé prvky x
shodují či neshodují s daným vzorem).
sub
a gsub
navrací vektor řetězců stejné délky a vlastností jako x
(po možném převedení na řetězec). Prvky vektoru řetězců x
, které nejsou nahrazeny, budou navráceny nezměněné (včetně deklarovaného kódování). Pokud se useBytes = FALSE
, bude výsledek s nahrazenými non-ASCII znaky v UTF-8 se značeným kódováním (např. pokud je vstup v UTF-8 anebo v případě multibajtového místního nastavení, není-li fixed = TRUE
). Takový řetězec muže být překódován zpět pomocí enc2native
.
regexpr
navrací vektor typu integer stejné délky jako text
, který nás informuje, na které pozici v prvku došlo ke shodě se vzorem. V přípdě, že nedošlo, je vrácena hodnota -1.Dále pak navrací další vektor typu integer s vlastností "match.length"
, který udává délku shodovaného textu (pokud nebyla shoda, tak -1). Obojí, pozice i délka, jsou v jednotkách znaků. Pokud se však useBytes = TRUE
, jsou v jednotkách bajtů (jelikož je toto srovnávání určeno pouze pro znaky ASCII, může být pro výsledek v obou případech nastavená vlastnost useBytes = TRUE
). Pokud jsou použity pojmenované podvýrazy, jsou zpřístupněny další vlastnoosti jako "capture.start"
, "capture.length"
a "capture.names"
.
gregexpr
navrací seznam stejné délky jako text
. Každý prvek seznamu má stejný formát jako navrácená hodnota u regexpr
. Odlišností je, že došlo-li na více pozicích v prvku ke shodě se vzorem, jsou navráceny všechny pozice shody (nikoliv pouze ta první).
regexec
navrací seznam stejné délky jako text
, kterého každý prvek je buďto -1, pokud nedošlo ke shodě, nebo posloupnost celých čísel udávajících pozice shody i všech podřetězců, které odpovídají podvýrazům v pattern
. Dále je navrácen vektor s vlastností "match.length"
, který udává délku shody (nebo -1, pokud nebyla žádná shoda). Interpretace pozicí, délek i vlastností je obdobná jako u funkce regexpr
.
Pokud srovnávání selže z důvodu limitů zdroje (platí obzvlášť pro PCRE), je na to ve výstupu pohlíženo jako na neshodu, obvykle doprovázené varovným hlášením.
Varování
Mód POSIX 1003.2 u funkcí gsub
a gregexpr
nepracuje správně s opakujícími se hranicemi slova (např. pattern = "b"
). Pro taková srovnávání použijte perl = TRUE
(tento mód však nemusí pracovat dle očekávání se vstupy obsahujícími non-ASCII znaky, neboť význam ‘slova’ závisí na systému).
Poznámky k výkonu
Pokud provádíte mnohá srovnávání s pomocí regulárních výrazů, včetně takových na velmi dlouhých řetězcích, budete chtít zvážit, kterou metodu použít. Obvykle je PCRE rychlejší než ostatní regulární stroje, i přes fixed = TRUE
(zejména pokud je vzor shodný pouze párkrát).
Pokud pracujete v jednobajtovém místním nastavení a máte řetězce se značeným UTF-8, které mohou být reprezentovány ve zmíněném místním nastavení, tak jejich převod na jeden UTF-8 řetězec příměje provést srovnávání v Unicode.
Pokud máte možnost použít useBytes = TRUE
, tak řetězec nebude před srovnáváním kontrolován, což urychlí samotný proces srovnávání. Často je srovnávání založené na bajtech dostačující v místním nastavení UTF-8.
Srovnávání založené na PCRE jako výchozí nastavení vynakládá dodatečné usilí na ‘prozkoumání’ kompilovaného vzoru, má-li x
/text
délku alespoň 10. Od verze R 3.4.0 může být toto prozkoumání provedeno s použitím kompilátoru PCRE JIT na platformách, kde je k dispozici (viz pcre_config
). Detaily lze upřesnit pomocí options
PCRE_study
a PCRE_use_JIT
. (Porovnání časové náročnosti může být provedeno za použití ‘tests/PCRE.R’ ve zdrojých R). Ti, kteří pracují s PCRE a velmi dlouhými řetězci, mohou upravit maximální velikost JIT zásobníku nastavením proměnné prostředí R_PCRE_JIT_STACK_MAXSIZE před použitím JIT na hodnotu mezi 1
a 1000
v MB: výchozí hodnota je 64
. (Potom by také bylo vhodné nastavit option PCRE_limit_recursion
.)
Zdroj
C kód pro srovnávání za pomocí regulárních výrazů stylu POSIX se v průběhu let změnil. Od verze R 2.10.0 (Říjen 2009) je používána TRE knihovna od Ville Laurikari (http://laurikari.net/tre/). Standard POSIX nechává prostor na interpretaci, zejména obsluhou neplatných regulárních výrazů a porovnáváním znakových sad, tedy výsledky se mohou mírně lišit oproti těm z dřívějška.
Pro srovnávání ve stylu Perl je použito PCRE (http://www.pcre.org): opět se můžou výsledky mírně lišit v závislosti na použité verzi.
Reference
Becker, R. A., Chambers, J. M. and Wilks, A. R. (1988) The New S Language. Wadsworth & Brooks/Cole (grep
)
Příklad
grep("[a-z]", letters)
txt <- c("arm","foot","lefroo", "bafoobar")
if(length(i <- grep("foo", txt)))
cat("'foo' appears at least once innt", txt, "n")
i # 2 a 4
txt[i]
## Zdvojte všechna 'a' nebo 'b'; "" musí být uniknutý, tzn. 'zdvojený'
gsub("([ab])", "1_1_", "abc and ABC")
txt <- c("The", "licenses", "for", "most", "software", "are",
"designed", "to", "take", "away", "your", "freedom",
"to", "share", "and", "change", "it.",
"", "By", "contrast,", "the", "GNU", "General", "Public", "License",
"is", "intended", "to", "guarantee", "your", "freedom", "to",
"share", "and", "change", "free", "software", "--",
"to", "make", "sure", "the", "software", "is",
"free", "for", "all", "its", "users")
( i <- grep("[gu]", txt) ) # indices
stopifnot( txt[i] == grep("[gu]", txt, value = TRUE) )
## Všimněte si, že v místních nastevních jako en_US, je takto zahrnuto B, protože
## pořadí porovnávání je aAbBcCdDe ...
(ot <- sub("[b-e]",".", txt))
txt[ot != gsub("[b-e]",".", txt)]#- gsub provede "celskové" nahrazení
txt[gsub("g","#", txt) !=
gsub("g","#", txt, ignore.case = TRUE)] # slova "G"
regexpr("en", txt)
gregexpr("e", txt)
## Používání funkce grepl() profiltorvání
## Nalezení funkcí s názvy argumentů shodujících se s "warn":
findArgs <- function(env, pattern) {
nms <- ls(envir = as.environment(env))
nms <- nms[is.na(match(nms, c("F","T")))] # <-- work around "checking hack"
aa <- sapply(nms, function(.) { o <- get(.)
if(is.function(o)) names(formals(o)) })
iw <- sapply(aa, function(a) any(grepl(pattern, a, ignore.case=TRUE)))
aa[iw]
}
findArgs("package:base", "warn")
## zakončení mezerou
str <- "Now is the time "
sub(" +$", "", str) ## spaces only
## Co je myšleno 'bílým znakem' závisí na místním nastavení
sub("[[:space:]]+$", "", str) ## white space, POSIX-style
## To, co považovalo PCRE za bílý znak, se změnilo ve verzi 8.34: viz ?regex
sub("s+$", "", str, perl = TRUE) ## bílý znak stylu PCRE
## Kapitalizace
txt <- "test of capitalization"
gsub("(w)(w*)", "U1L2", txt, perl=TRUE)
gsub("b(w)", "U1", txt, perl=TRUE)
txt2 <- "useRs may fly into JFK or laGuardia"
gsub("(w)(w*)(w)", "U1E2U3", txt2, perl=TRUE)
sub("(w)(w*)(w)", "U1E2U3", txt2, perl=TRUE)
## pojmenované podvýrazy
notables <- c(" Ben Franklin and Jefferson Davis",
"tMillard Fillmore")
# názvy skupin 'first' a 'last'
name.rex <- "(?<first>[[:upper:]][[:lower:]]+) (?<last>[[:upper:]][[:lower:]]+)"
(parsed <- regexpr(name.rex, notables, perl = TRUE))
gregexpr(name.rex, notables, perl = TRUE)[[2]]
parse.one <- function(res, result) {
m <- do.call(rbind, lapply(seq_along(res), function(i) {
if(result[i] == -1) return("")
st <- attr(result, "capture.start")[i, ]
substring(res[i], st, st + attr(result, "capture.length")[i, ] - 1)
}))
colnames(m) <- attr(result, "capture.names")
m
}
parse.one(notables, parsed)
## Rozložení URL na jeho části
## Příklad od LT (http://www.cs.uiowa.edu/~luke/R/regexp.html).
x <- "http://stat.umn.edu:80/xyz"
m <- regexec("^(([^:]+)://)?([^:/]+)(:([0-9]+))?(/.*)", x)
m
regmatches(x, m)
## Prvek 3 je protokol, 4 je host, 6 je port a 7 je umístění
## Můžeme toho využít, pokud potřebujeme vyextrahovat části URL:
URL_parts <- function(x) {
m <- regexec("^(([^:]+)://)?([^:/]+)(:([0-9]+))?(/.*)", x)
parts <- do.call(rbind,
lapply(regmatches(x, m), `[`, c(3L, 4L, 6L, 7L)))
colnames(parts) <- c("protocol","host","port","path")
parts
}
URL_parts(x)
## Zatím nemáme funci gregexec(), ovšem lze ji napodobnit
## spuštěním regexec() na regmatches získaných cestou gregexpr(). Např.:
pattern <- "([[:alpha:]]+)([[:digit:]]+)"
s <- "Test: A1 BC23 DEF456"
lapply(regmatches(s, gregexpr(pattern, s)),
function(e) regmatches(e, regexec(pattern, e)))