[R] gsub syntax

Prof Brian Ripley ripley at stats.ox.ac.uk
Sun Nov 27 17:41:40 CET 2005


R is blameless here: it works as documented and in the same way as 
POSIX tools.  It agrees with 'sed' using the same syntax (modulo the 
shell-specific quoting rules) e.g. in csh

    % echo 1973 | sed 's/[19|20]\([0-9][0-9]\)/\1/g'
    973
    % echo 1973 | sed 's/\([19|20]\)\([0-9][0-9]\)/-\1-\2-/g'
    -1-97-3
    % echo "73 74 02 1973 1974 2002" | sed 's/[19|20]\([0-9][0-9]\)/\1/g'
    73 74 02 973 974 002

so what happened when you were 'comparing with sed'?

"[19|20]" is a character class (containing five characters) matching one 
character, not a match for two characters as you seem to imagine.  It does 
not mean the same as "19|20", which is what you seem to have intended (and 
you seem only to want to do the substitution once on each string, so why 
use gsub?):

> sub("19|20([0-9][0-9])", "\\1", dates)
[1] "73" "74" "02" "73" "74" "02"

A more direct way which would work e.g. for 1837 would be

sub(".*([0-9]{2}$)", "\\1", dates)

or even better (locale-independent)

sub(".*([[:digit:]]{2}$)", "\\1", dates)

Current versions of R have a help page ?regexp explaining what regexps 
are.  Even 2.0.1 did, although you were asked to update *before* posting 
(see the posting guide).  It was unambiguous:

    A _character class_ is a list of characters enclosed by '[' and
    ']' matches any single character in that list ...
                    ^^^^^^
    ...  Note that alternation does not work inside character classes,
    where \code{|} has its literal meaning.


On Sun, 27 Nov 2005, John Logsdon wrote:

> Hello
>
> I know that R's string functions are not as extensive as those of Unix but
> I need to do some text handling totally within an R environment because
> the target is a Windows system which will not have the corresponding shell
> utilities, sed, awk etc.
> Can anyone explain the following gsub phenomenon to me:
>
>> dates<-c("73","74","02","1973","1974","2002")
>
> I want to take just the last two digits where it is a 4-digit year and
> both digits when it is a 2-digit year.  I should be able to use substr but
> measurement from the string end (with a negative counter or something) is
> not implemented:

Why 'should' it work in a different way to that documented?

>> substr(dates,3,4)
> [1] ""   ""   ""   "73" "74" "02"
>> substr(dates,-2,4)
> [1] "73"   "74"   "02"   "1973" "1974" "2002"
>> substr(dates,4,-2)
> [1] "" "" "" "" "" ""
>
> So I tried gsub:
>
>> gsub("[19|20]([0-9][0-9])","\\1",dates)
> [1] "73"  "74"  "02"  "973" "974" "002"
>
> As I understand it (and comparing with sed), the \\1 should take the first
> bracketed string but clearly this doesn't work.
> If I try what should also work:
>
>> gsub("[19|20]([0-9])([0-9])","\\1\\2",dates)
> [1] "73"  "74"  "02"  "973" "974" "002"

> On the other hand the following does work:
>
>> gsub("[19|20]([0-9])([0-9])","\\2",dates)
> [1] "73" "74" "02" "73" "74" "02"
>
> So it appears that the substitution takes one character extra to the left
> but the following indicates that the lower limit of the selected range is
> also at fault:
>> s<-c("1","12","123","1234","12345","123456")
>> gsub("[12]([4-6]*)","",s)
> [1] ""     ""     "3"    "34"   "345"  "3456"
>
> Probably more elegant examples could be constructed that could home in on
> the issue.
> The version is R 2.0.1 on Linux so perhaps it is a little old now.
>
> Questions:
>
> 1) Am I misunderstanding the gsub use?

Yes.

> 2) Was it a bug that has since been corrected?

Unfortunately the bug reported two years ago in

> library(fortunes); fortune("WTFM")

still seems extant.  See the posting guide for advice on how to correct 
it.


-- 
Brian D. Ripley,                  ripley at stats.ox.ac.uk
Professor of Applied Statistics,  http://www.stats.ox.ac.uk/~ripley/
University of Oxford,             Tel:  +44 1865 272861 (self)
1 South Parks Road,                     +44 1865 272866 (PA)
Oxford OX1 3TG, UK                Fax:  +44 1865 272595




More information about the R-help mailing list