29

In R, I want to convert

t1 <- c('this.text', 'next.text')
"this.text" "next.text"

to

'ThisText' 'NextText'

I have tried

gsub('\\..', '', t1)

But this gives me

"thisext" "nextext"

as it does not replace the letter after the period.

Probably really easy but I can't work it out.

Artem Klevtsov
  • 9,193
  • 6
  • 52
  • 57
Tom Liptrot
  • 2,273
  • 21
  • 23

6 Answers6

24

Alternatively a regex based solution:

t1 <- c('this.text', 'next.text')

# capitalize first letter
t2 <- sub('^(\\w?)', '\\U\\1', t1, perl=T)

# remove points and capitalize following letter
gsub('\\.(\\w?)', '\\U\\1', t2, perl=T)
[1] "ThisText" "NextText"

Edit: some explanations

sub('^(\\w?)', '\\U\\1', t1, perl=T), sub is sufficient here because we are only interested in the first match. Then the first alphanumeric character is matched at the beginning of each string with ^(\\w?). The parenthesis are needed for back reference in the replacement part of the function. For the replacement \\U is used to capitalize everything that comes afterwards (which is the first character).

The same principle is applied in gsub('\\.(\\w?)', '\\U\\1', t2, perl=T) with the only difference that not the first character is matched, but every ..

johannes
  • 14,043
  • 5
  • 40
  • 51
  • Very nice approach. I can usually figure it out in regex but it takes me some thinking. Great work +1 May I request a small edit explaining a little bit about the magic of your regex for future searchers? – Tyler Rinker Jul 26 '12 at 15:47
  • thanks for that, I added some explanations, hopefully this makes it easier to understand. – johannes Jul 26 '12 at 15:59
  • 2
    Alternatively, if you use lookahead assertions, you can do it in one line: `gsub("(?:(?=\\b)|\\.)([[:alpha:]])", "\\U\\1", t1, perl=TRUE)` – sebastian-c Jul 27 '12 at 07:52
  • 2
    Actually, mine can be simplified further to not require the lookahead: `gsub("(?:\\b|\\.)([[:alpha:]])", "\\U\\1", t1, perl=TRUE)`. Sadly, @TylerRinker, the speed increase is negligible. – sebastian-c Jul 30 '12 at 08:28
18

Here's one approach but with regex there's probably better ones:

t1 <- c('this.text', 'next.text')

camel <- function(x){ #function for camel case
    capit <- function(x) paste0(toupper(substring(x, 1, 1)), substring(x, 2, nchar(x)))
    sapply(strsplit(x, "\\."), function(x) paste(capit(x), collapse=""))
}

camel(t1)

This yields:

> camel(t1)
[1] "ThisText" "NextText"

EDIT: As a curiosity I microbenchmarked the 4 answers (TOM=original poster, TR=myself, JMS=jmsigner & SB=sebastion; commented on jmsigner's post) and found the non regex answers to be faster. I would have assumed them slower.

   expr     min      lq  median      uq      max
1 JMS() 183.801 188.000 197.796 201.762  349.409
2  SB()  93.767  97.965 101.697 104.963  147.881
3 TOM()  75.107  82.105  85.370  89.102 1539.917
4  TR()  70.442  76.507  79.772  83.037  139.484

enter image description here

Tyler Rinker
  • 108,132
  • 65
  • 322
  • 519
9

Actually I think I just worked this out from the help file for toupper:

camel <- function(x) {     
     s <- strsplit(x, "\\.")[[1]]     
     paste(toupper(substring(s, 1,1)), substring(s, 2),           
     sep="", collapse="") 
 }    

camel(t1) 
sapply(t1,camel)  
this.text  next.text  
"ThisText" "NextText"  
Tom Liptrot
  • 2,273
  • 21
  • 23
9

tocamel from rapportools package does what you want:

> library(rapportools)
> example(tocamel)

tocaml> tocamel("foo.bar")
tocaml>     ## [1] "fooBar"
tocaml> 
tocaml>     tocamel("foo.bar", upper = TRUE)
tocaml>     ## [1] "FooBar"
tocaml> 
tocaml>     tocamel(c("foobar", "foo.bar", "camel_case", "a.b.c.d"))
tocaml>     ## [1] "foobar"    "fooBar"    "camelCase" "aBCD"
tocaml> 

Updated:

Another simply and fast solution (like @rengis):

camel2 <- function(x) {
    gsub("(^|[^[:alnum:]])([[:alnum:]])", "\\U\\2", x, perl = TRUE)
}
camel2(t1)
#> [1] "ThisText" "NextText"

Comparison with the @TylerRinker solution:

identical(camel(t1), camel2(t1))
#> [1] TRUE
microbenchmark::microbenchmark(camel(t1), camel2(t1))
#> Unit: microseconds
#>        expr    min      lq     mean  median      uq     max neval cld
#>   camel(t1) 76.378 79.6520 82.21509 81.5065 82.7095 151.867   100   b
#>  camel2(t1) 15.864 16.9425 19.76000 20.9690 21.9735  38.246   100  a
Artem Klevtsov
  • 9,193
  • 6
  • 52
  • 57
6

Here another solution via the snakecase package:

install.packages("snakecase")
library(snakecase)

to_upper_camel_case(t1)
#> [1] "ThisText" "NextText"

Githublink: https://github.com/Tazinho/snakecase

Taz
  • 546
  • 5
  • 9
6

The make_clean_names() function in the janitor package has a function that can be used for this.

In your case:

t1 <- c('this.text', 'next.text')
janitor::make_clean_names(t1, case = "big_camel")
#> [1] "ThisText" "NextText"

The parameter case can be one of many:

“snake”, “small_camel”, “big_camel”, “screaming_snake”, “parsed”, “mixed”, “lower_upper”, “upper_lower”, “swap”, “all_caps”, “lower_camel”, “upper_camel”, “internal_parsing”, “none”, “flip”, “sentence”, “random”, “title”

Created on 2021-10-13 by the reprex package (v2.0.1)

Gorka
  • 3,555
  • 1
  • 31
  • 37