Keep only the first letter of each word after a comma

Viewed 262

I have strings like Sacher, Franz Xaver or Nishikawa, Kiyoko.

Using R, I want to change them to Sacher, F. X. or Nishikawa, K..

In other words, the first letter of each word after the comma should be retained with a dot (and a whitespace if another word follows).

Here is a related response, but it cannot be applied to my case 1:1 as it does not have a comma in its strings; it seems that the simple addition of (<?=, ) does not work.

E.g. in the following attempts, gsub() replaces everything, while my str_replace_all()-attempt leads to an error:

TEST <- c("Sacher, Franz Xaver", "Nishikawa, Kiyoko", "Al-Assam, Muhammad")

# first attempt
# (resembles the response from the other thread)
gsub('\\b(\\pL)\\pL{2,}|.','\\U\\1', TEST, perl = TRUE)

# second attempt
# error: "Incorrect unicode property"
stringr::str_replace_all(TEST, '(?<=, )\\b(\\pL)\\pL{2,}|.','\\U\\1') 

I would be grateful for your help!

3 Answers

You can use

gsub("(*UCP)^[^,]+(*SKIP)(*F)|\\b(\\p{L})\\p{L}*", "\\U\\1.", TEST, perl=TRUE)

See the regex demo. Details:

  • (*UCP) - the PCRE verb that will make \b Unicode aware
  • ^[^,]+(*SKIP)(*F) - start of string and then any zero or more chars other than a comma, and then the match is failed and skipped, the next match starts at the location where the failure occurred
  • | - or
  • \b - word boundary
  • (\p{L}) - Group 1: any Unicode letter
  • \p{L}* - zero or more Unicode letters

See the R demo:

TEST <- c("Sacher, Franz Xaver", "Nishikawa, Kiyoko", "Al-Assam, Muhammad")
gsub("(*UCP)^[^,]+(*SKIP)(*F)|\\b(\\p{L})\\p{L}*", "\\U\\1.", TEST, perl=TRUE)
## => [1] "Sacher, F. X." "Nishikawa, K." "Al-Assam, M." 

A crude approach splitting the string :

TEST <- c("Sacher, Franz Xaver", "Nishikawa, Kiyoko", "Al-Assam, Muhammad")

sapply(strsplit(TEST, '\\s+'), function(x) 
      paste0(x[1], paste0(substr(x[-1], 1, 1), collapse = '.'), '.'))

#[1] "Sacher,F.X."  "Nishikawa,K." "Al-Assam,M." 

An approach using multiple backreference:

gsub("(\\b\\w+,\\s)(\\b\\w).*(\\b\\w)*", "\\1\\2.\\3", TEST)
[1] "Sacher, F."    "Nishikawa, K." "Al-Assam, M." 

Here, we use three capturing groups to refer back to in gsub's replacment argument via backreference:

  • (\\b\\w+,\\s): this, first, group captures the last name plus the comma followed by whitespace
  • (\\b\\w): this, second, group captures the initial of the first name
  • (\\b\\w): this, third, group captures the initial of the middle name
Related