Math
Math

Reputation: 2436

Extraction of a name from a string with variable number of separators

I would like to extract part of a foldername which as the form 123456_Letters_CAPITAL_name_extension.

The name can be LETTERS123, LETTERS_123_LETTERS or LETTERS_LETTERS_123.

Currently, I'm extracting the name with unlist(strsplit(foldername , sep="_"))[4,length(unlist(strsplit(foldername , sep="_")))-1]

But I would like to be able to extract it if the _CAPITAL part is not present (it would be 3 instead of 4 but I would like to have a general way of doing it).

130615_Screen_II_SN_KB_3_lxb/, 130615_Screen_II_AL343_lxb/, 130615_Screen_II_HK_344_LM_lxb/ are representative examples of complete foldername

I tried but could not figure any regex that would do that. Any idea would be helpful.

Upvotes: 0

Views: 67

Answers (2)

Toto
Toto

Reputation: 91430

How about this one:

^\d+_[a-zA-Z]+_(?:[A-Z]+_)?([A-Z]+\w+)_[^_]+$

The name will be in group 1.

A perl way to test it:

my $re = qr~^\d+_[a-zA-Z]+_(?:[A-Z]+_)?([A-Z]+\w+)_[^_]+$~;
while(<DATA>) {
    chomp;
    say $1 if /$re/;
}
__DATA__
130615_Screen_II_SN_KB_3_lxb/
130615_Screen_II_AL343_lxb/
130615_Screen_II_HK_344_LM_lxb/
130615_Screen_HK_344_LM_lxb/

output:

SN_KB_3
AL343
HK_344_LM
HK_344_LM

Explanation:

The regular expression:

^\d+_[a-zA-Z]+_(?:[A-Z]+_)?([A-Z]+\w+)_[^_]+$

matches as follows:

NODE                     EXPLANATION
----------------------------------------------------------------------
  ^                        the beginning of the string
----------------------------------------------------------------------
  \d+                      digits (0-9) (1 or more times (matching
                           the most amount possible))
----------------------------------------------------------------------
  _                        '_'
----------------------------------------------------------------------
  [a-zA-Z]+                any character of: 'a' to 'z', 'A' to 'Z'
                           (1 or more times (matching the most amount
                           possible))
----------------------------------------------------------------------
  _                        '_'
----------------------------------------------------------------------
  (?:                      group, but do not capture (optional
                           (matching the most amount possible)):
----------------------------------------------------------------------
    [A-Z]+                   any character of: 'A' to 'Z' (1 or more
                             times (matching the most amount
                             possible))
----------------------------------------------------------------------
    _                        '_'
----------------------------------------------------------------------
  )?                       end of grouping
----------------------------------------------------------------------
  (                        group and capture to \1:
----------------------------------------------------------------------
    [A-Z]+                   any character of: 'A' to 'Z' (1 or more
                             times (matching the most amount
                             possible))
----------------------------------------------------------------------
    \w+                      word characters (a-z, A-Z, 0-9, _) (1 or
                             more times (matching the most amount
                             possible))
----------------------------------------------------------------------
  )                        end of \1
----------------------------------------------------------------------
  _                        '_'
----------------------------------------------------------------------
  [^_]+                    any character except: '_' (1 or more times
                           (matching the most amount possible))
----------------------------------------------------------------------
  $                        before an optional \n, and the end of the
                           string
----------------------------------------------------------------------

Upvotes: 2

CHP
CHP

Reputation: 17189

Let's tackle the problem step by step. x below covers all possible cases as mentioned in question. (OP please confirm)

x <- c("123456_Letters_CAPITAL_LETTERS123_extension/", "123456_Letters_CAPITAL_LETTERS_123_LETTERS_extension/", "123456_Letters_CAPITAL_LETTERS_LETTERS_123_extension/", 
    "123456_Letters_LETTERS123_extension/", "123456_Letters_LETTERS_123_LETTERS_extension/", "123456_Letters_LETTERS_LETTERS_123_extension/")
# Lets strip out the parts which we can first..
y <- gsub("[0-9]+_[A-Z]+[a-z]*_(.*)_[a-z]+/", "\\1", x)
y
## [1] "CAPITAL_LETTERS123"          "CAPITAL_LETTERS_123_LETTERS" "CAPITAL_LETTERS_LETTERS_123" "LETTERS123"                 
## [5] "LETTERS_123_LETTERS"         "LETTERS_LETTERS_123" 


#Now we can see that if you have 3 or 1 underscore 
#you need to strip out first part


ifelse(sapply(gregexpr("_", y), FUN = function(X) length(X[X != -1])) %in% c(1, 3), gsub("[A-Z]+_(.*)", "\\1", y), y)
## [1] "LETTERS123"          "LETTERS_123_LETTERS" "LETTERS_LETTERS_123" "LETTERS123"          "LETTERS_123_LETTERS"
## [6] "LETTERS_LETTERS_123"

Upvotes: 1

Related Questions