Parsing a path to components

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • eliben

    Parsing a path to components

    Hello,

    os.path.split returns the head and tail of a path, but what if I want
    to have all the components ? I could not find a portable way to do
    this in the standard library, so I've concocted the following
    function. It uses os.path.split to be portable, at the expense of
    efficiency.

    ----------------------------------
    def parse_path(path ):
    """ Parses a path to its components.

    Example:
    parse_path("C:\ \Python25\\lib\ \site-packages\
    \zipextimporter .py")

    Returns:
    ['C:\\', 'Python25', 'lib', 'site-packages',
    'zipextimporter .py']

    This function uses os.path.split in an attempt to be portable.
    It costs in performance.
    """
    lst = []

    while 1:
    head, tail = os.path.split(p ath)

    if tail == '':
    if head != '': lst.insert(0, head)
    break
    else:
    lst.insert(0, tail)
    path = head

    return lst
    ----------------------------------

    Did I miss something and there is a way to do this standardly ?
    Is this function valid, or will there be cases that will confuse it ?

    Thanks in advance
    Eli
  • s0suk3@gmail.com

    #2
    Re: Parsing a path to components

    On Jun 7, 12:55 am, eliben <eli...@gmail.c omwrote:
    Hello,
    >
    os.path.split returns the head and tail of a path, but what if I want
    to have all the components ? I could not find a portable way to do
    this in the standard library, so I've concocted the following
    function. It uses os.path.split to be portable, at the expense of
    efficiency.
    >
    ----------------------------------
    def parse_path(path ):
        """ Parses a path to its components.
    >
            Example:
                parse_path("C:\ \Python25\\lib\ \site-packages\
    \zipextimporter .py")
    >
                Returns:
                ['C:\\', 'Python25', 'lib', 'site-packages',
    'zipextimporter .py']
    >
            This function uses os.path.split in an attempt to be portable.
            It costs in performance.
        """
        lst = []
    >
        while 1:
            head, tail = os.path.split(p ath)
    >
            if tail == '':
                if head != '': lst.insert(0, head)
                break
            else:
                lst.insert(0, tail)
                path = head
    >
        return lst
    ----------------------------------
    >
    Did I miss something and there is a way to do this standardly ?
    Is this function valid, or will there be cases that will confuse it ?
    >
    You can just split the path on `os.sep', which contains the path
    separator of the platform on which Python is running:

    components = pathString.spli t(os.sep)

    Sebastian

    Comment

    • Marc 'BlackJack' Rintsch

      #3
      Re: Parsing a path to components

      On Fri, 06 Jun 2008 23:57:03 -0700, s0suk3 wrote:
      You can just split the path on `os.sep', which contains the path
      separator of the platform on which Python is running:
      >
      components = pathString.spli t(os.sep)
      Won't work for platforms with more than one path separator and if a
      separator is repeated. For example r'\foo\\bar/baz//spam.py' or:

      In [140]: os.path.split(' foo//bar')
      Out[140]: ('foo', 'bar')

      In [141]: 'foo//bar'.split(os.s ep)
      Out[141]: ['foo', '', 'bar']

      Ciao,
      Marc 'BlackJack' Rintsch

      Comment

      • eliben

        #4
        Re: Parsing a path to components

        On Jun 7, 10:15 am, Marc 'BlackJack' Rintsch <bj_...@gmx.net wrote:
        On Fri, 06 Jun 2008 23:57:03 -0700, s0suk3 wrote:
        You can just split the path on `os.sep', which contains the path
        separator of the platform on which Python is running:
        >
        components = pathString.spli t(os.sep)
        >
        Won't work for platforms with more than one path separator and if a
        separator is repeated. For example r'\foo\\bar/baz//spam.py' or:
        >
        In [140]: os.path.split(' foo//bar')
        Out[140]: ('foo', 'bar')
        >
        In [141]: 'foo//bar'.split(os.s ep)
        Out[141]: ['foo', '', 'bar']
        >
        Ciao,
        Marc 'BlackJack' Rintsch
        Can you recommend a generic way to achieve this ?
        Eli

        Comment

        • s0suk3@gmail.com

          #5
          Re: Parsing a path to components

          On Jun 7, 3:15 am, Marc 'BlackJack' Rintsch <bj_...@gmx.net wrote:
          On Fri, 06 Jun 2008 23:57:03 -0700, s0suk3 wrote:
          You can just split the path on `os.sep', which contains the path
          separator of the platform on which Python is running:
          >
          components = pathString.spli t(os.sep)
          >
          Won't work for platforms with more than one path separator and if a
          separator is repeated.  For example r'\foo\\bar/baz//spam.py' or:
          >
          In [140]: os.path.split(' foo//bar')
          Out[140]: ('foo', 'bar')
          >
          In [141]: 'foo//bar'.split(os.s ep)
          Out[141]: ['foo', '', 'bar']
          >
          But those are invalid paths, aren't they? If you have a jumble of a
          path, I think the solution is to call os.path.normpat h() before
          splitting.

          Sebastian

          Comment

          • Marc 'BlackJack' Rintsch

            #6
            Re: Parsing a path to components

            On Sat, 07 Jun 2008 02:15:07 -0700, s0suk3 wrote:
            On Jun 7, 3:15 am, Marc 'BlackJack' Rintsch <bj_...@gmx.net wrote:
            >On Fri, 06 Jun 2008 23:57:03 -0700, s0suk3 wrote:
            You can just split the path on `os.sep', which contains the path
            separator of the platform on which Python is running:
            >>
            components = pathString.spli t(os.sep)
            >>
            >Won't work for platforms with more than one path separator and if a
            >separator is repeated.  For example r'\foo\\bar/baz//spam.py' or:
            >>
            >In [140]: os.path.split(' foo//bar')
            >Out[140]: ('foo', 'bar')
            >>
            >In [141]: 'foo//bar'.split(os.s ep)
            >Out[141]: ['foo', '', 'bar']
            >>
            >
            But those are invalid paths, aren't they?
            No. See `os.altsep` on Windows. And repeating separators is allowed too.

            Ciao,
            Marc 'BlackJack' Rintsch

            Comment

            • Mark Tolonen

              #7
              Re: Parsing a path to components


              "eliben" <eliben@gmail.c omwrote in message
              news:e5fd542f-56d2-4ec0-a3a7-aa1ee106c624@a7 0g2000hsh.googl egroups.com...
              On Jun 7, 10:15 am, Marc 'BlackJack' Rintsch <bj_...@gmx.net wrote:
              >On Fri, 06 Jun 2008 23:57:03 -0700, s0suk3 wrote:
              You can just split the path on `os.sep', which contains the path
              separator of the platform on which Python is running:
              >>
              components = pathString.spli t(os.sep)
              >>
              >Won't work for platforms with more than one path separator and if a
              >separator is repeated. For example r'\foo\\bar/baz//spam.py' or:
              >>
              >In [140]: os.path.split(' foo//bar')
              >Out[140]: ('foo', 'bar')
              >>
              >In [141]: 'foo//bar'.split(os.s ep)
              >Out[141]: ['foo', '', 'bar']
              >>
              >Ciao,
              > Marc 'BlackJack' Rintsch
              >
              Can you recommend a generic way to achieve this ?
              Eli
              >>import os
              >>from os.path import normpath,abspat h
              >>x=r'\foo\\b ar/baz//spam.py'
              >>normpath(x)
              '\\foo\\bar\\ba z\\spam.py'
              >>normpath(absp ath(x))
              'C:\\foo\\bar\\ baz\\spam.py'
              >>normpath(absp ath(x)).split(o s.sep)
              ['C:', 'foo', 'bar', 'baz', 'spam.py']

              -Mark

              Comment

              • Duncan Booth

                #8
                Re: Parsing a path to components

                "Mark Tolonen" <M8R-yfto6h@mailinat or.comwrote:
                >Can you recommend a generic way to achieve this ?
                >Eli
                >
                >>>import os
                >>>from os.path import normpath,abspat h
                >>>x=r'\foo\\ba r/baz//spam.py'
                >>>normpath(x )
                '\\foo\\bar\\ba z\\spam.py'
                >>>normpath(abs path(x))
                'C:\\foo\\bar\\ baz\\spam.py'
                >>>normpath(abs path(x)).split( os.sep)
                ['C:', 'foo', 'bar', 'baz', 'spam.py']
                That gets a bit messy with UNC pathnames. With the OP's code the double
                backslah leadin is preserved (although arguably it has split one time too
                many, '\\\\frodo' would make more sense as the first element:
                >>parse_path(r' \\frodo\foo\bar ')
                ['\\\\', 'frodo', 'foo', 'bar']

                With your code you just get two empty strings as the leadin:
                >>normpath(absp ath(r'\\frodo\f oo\bar')).split (os.sep)
                ['', '', 'frodo', 'foo', 'bar']

                --
                Duncan Booth http://kupuguy.blogspot.com

                Comment

                • Scott David Daniels

                  #9
                  Re: Parsing a path to components

                  eliben wrote:
                  .... a prety good try ...
                  def parse_path(path ):
                  """..."""
                  By the way, the comment is fine. I am going for brevity here.
                  lst = []
                  while 1:
                  head, tail = os.path.split(p ath)
                  if tail == '':
                  if head != '': lst.insert(0, head)
                  break
                  else:
                  lst.insert(0, tail)
                  path = head
                  return lst
                  ----------------------------------
                  >
                  Did I miss something and there is a way to do this standardly ?
                  Nope, the requirement is rare.
                  Is this function valid, or will there be cases that will confuse it ?
                  parse_path('/a/b/c//d/')

                  Try something like:
                  def parse_path(path ):
                  '''...same comment...'''
                  head, tail = os.path.split(p ath)
                  result = []
                  if not tail:
                  if head == path:
                  return [head]
                  # Perhaps result = [''] here to an indicate ends-in-sep
                  head, tail = os.path.split(h ead)
                  while head and tail:
                  result.append(t ail)
                  head, tail = os.path.split(h ead)
                  result.append(h ead or tail)
                  result.reverse( )
                  return result

                  --Scott David Daniels
                  Scott.Daniels@A cm.Org

                  Comment

                  Working...