Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ksh-style left and right string stripping up to matched expression?

How can one strip the left parts and right parts off strings up to a matching expression as in ksh?

For instance:

${name##*/}

${name%/*}

(see http://www.well.ox.ac.uk/~johnb/comp/unix/ksh.html for ksh examples).

I can't seem to figure out a simple way of doing this using re module or string module but I must be missing something.

like image 980
mathtick Avatar asked Jul 13 '10 15:07

mathtick


4 Answers

Ksh:

$ s='abc/def/ghi'
$ echo ${s%%/*}
abc
$ echo ${s%/*}
abc/def
$ echo ${s#*/}
def/ghi
$ echo ${s##*/}
ghi

Python:

>>> s='abc/def/ghi'
>>> print s[:s.find("/")]
abc
>>> print s[:s.rfind("/")]
abc/def
>>> print s[s.find("/")+1:]
def/ghi
>>> print s[s.rfind("/")+1:]
ghi

Edit:

To handle the case in which the pattern is missing, as pointed out by ΤΖΩΤΖΙΟΥ:

>>> s='abc/def/ghi'
>>> t='no slash here'
>>> print s[:s.find("/") % (len(s) + 1)]
abc
>>> print t[:t.find("/") % (len(t) + 1)]
no slash here
>>> print s[:s.rfind("/") % (len(s) + 1)]
abc/def
>>> print t[:t.rfind("/") % (len(t) + 1)]
no slash here
>>> print s[s.find("/")+1:]
def/ghi
>>> print t[t.find("/")+1:]
no slash here
>>> print s[s.rfind("/")+1:]
ghi
>>> print t[t.rfind("/")+1:]
no slash here
like image 129
Dennis Williamson Avatar answered Sep 28 '22 10:09

Dennis Williamson


${name##*/}

Is equivalent to:

re.match(".*?([^/]*)$")[1]

${name%/*}

Is equivalent to:

re.match("(.*?)[^/]*$")[1]
like image 36
Matt Joiner Avatar answered Sep 28 '22 12:09

Matt Joiner


There is no special status for "strip to the left", "strip to the right", etc. The one general method is re.sub -- for example, to "strip everything up to the last slash included" ("to the left" as ksh conceptualizes it):

name = re.sub(r'(.*/)(.*)', r'\2', name)

and to strip "the last slash and everything following" ("to the right" per ksh):

name = re.sub(r'(.*)/.*', r'\1', name)

These match as much as possible because the * in RE patterns is greedy; use *? instead for non-greedy matching ("as little as possible") instead.

like image 30
Alex Martelli Avatar answered Sep 28 '22 12:09

Alex Martelli


>>> def strip_upto_max(astring, pattern):
    "${astring##*pattern}"
    return astring.rpartition(pattern)[2]
>>> def strip_from_max(astring, pattern):
    "${astring%%pattern*}"
    return astring.partition(pattern)[0]
>>> def strip_upto(astring, pattern):
    "${astring#*pattern}"
    return astring.partition(pattern)[2]
>>> def strip_from(astring, pattern):
    "${astring%pattern*}"
    return astring.rpartition(pattern)[0]

>>> strip_from("hello there", " t")
'hello'
>>> strip_upto("hello there", " t")
'here'

>>> text= "left/middle/right"
>>> strip_from(text, "/")
'left/middle'
>>> strip_upto(text, "/")
'middle/right'
>>> strip_upto_max(text, "/")
'right'
>>> strip_from_max(text, "/")
'left'

But if your intention is to use it with paths, check whether the os.path.dirname (${name%/*}) and os.path.basename (${name##*/}) functions have the functionality you require.

like image 32
tzot Avatar answered Sep 28 '22 12:09

tzot