[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

head/tail split for path

Trans

7/26/2008 7:55:00 PM

I need to split a path by head/*tail.

Ex.

File.head_tail_split('home/foo/bar') #=> [ 'home', 'foo/bar' ]

Sure, I can write a clumsy loop like the following:

def File.head_tail_split(fname)
s = fname
t = []
h = nil
until s == '.'
t << h
s, h = *split(s)
end
return h, File.join(*t.compact)
end

But I'm betting there's a better way. Or maybe there's already an easy
way I'm overlooking?

T.

12 Answers

David A. Black

7/26/2008 9:04:00 PM

0

Hi --

On Sun, 27 Jul 2008, Trans wrote:

> I need to split a path by head/*tail.
>
> Ex.
>
> File.head_tail_split('home/foo/bar') #=> [ 'home', 'foo/bar' ]
>
> Sure, I can write a clumsy loop like the following:
>
> def File.head_tail_split(fname)
> s = fname
> t = []
> h = nil
> until s == '.'
> t << h
> s, h = *split(s)
> end
> return h, File.join(*t.compact)
> end
>
> But I'm betting there's a better way. Or maybe there's already an easy
> way I'm overlooking?

Check out the Pathname feature:

require 'pathname'

p = Pathname.new("a/b/c")

You get p.basename and p.dirname. Both return Pathname objects, but
they're quite string-like and easily converted.


David

--
Rails training from David A. Black and Ruby Power and Light:
Intro to Ruby on Rails July 21-24 Edison, NJ
* Advancing With Rails August 18-21 Edison, NJ
* Co-taught by D.A. Black and Erik Kastner
See http://www.r... for details and updates!

Trans

7/26/2008 9:45:00 PM

0

Hi David,

David A. Black wrote:
>
> Check out the Pathname feature:
>
> require 'pathname'
>
> p = Pathname.new("a/b/c")
>
> You get p.basename and p.dirname. Both return Pathname objects, but
> they're quite string-like and easily converted.

p = Pathname.new("a/b/c")

p.dirname #=> "a/b"
p.basename #=> "c"

But I need "a" and "b/c".

T.
--
Posted via http://www.ruby-....

David A. Black

7/26/2008 9:59:00 PM

0

Hi --

On Sun, 27 Jul 2008, Thomas Sawyer wrote:

> Hi David,
>
> David A. Black wrote:
>>
>> Check out the Pathname feature:
>>
>> require 'pathname'
>>
>> p = Pathname.new("a/b/c")
>>
>> You get p.basename and p.dirname. Both return Pathname objects, but
>> they're quite string-like and easily converted.
>
> p = Pathname.new("a/b/c")
>
> p.dirname #=> "a/b"
> p.basename #=> "c"
>
> But I need "a" and "b/c".

Whoops. Well, you could do:

require 'enumerator'
[path.to_enum(:ascend).to_a[1], path.basename]

or something like:

path.scan(/([^\/]+)\/(.*)/) # with the String path

Pathname#cleanpath might come in handy if you're rolling your own. So
might File::Separator.


David

--
Rails training from David A. Black and Ruby Power and Light:
Intro to Ruby on Rails July 21-24 Edison, NJ
* Advancing With Rails August 18-21 Edison, NJ
* Co-taught by D.A. Black and Erik Kastner
See http://www.r... for details and updates!

Bill Walton

7/27/2008 6:14:00 PM

0

Hi Trans,

Trans wrote:

> I need to split a path by head/*tail.
>
> Ex.
>
> File.head_tail_split('home/foo/bar') #=> [ 'home', 'foo/bar' ]
>

You could do like this.

def head_tail_split(fname)
components = fname.split('/')
[components.shirt, components.join('/')]
end

irb(main):001:0> fname = 'home/foo/bar'
=> "home/foo/bar"
irb(main):002:0> components = fname.split('/')
=> ["home", "foo", "bar"]
irb(main):003:0> [components.shift, components.join('/')]
=> ["home", "foo/bar"]

HTH,
Bill

Phlip

7/27/2008 6:20:00 PM

0

Bill Walton wrote:

> You could do like this.
>
> def head_tail_split(fname)
> components = fname.split('/')
> [components.shirt, components.join('/')]
> end
>
> irb(main):001:0> fname = 'home/foo/bar'
> => "home/foo/bar"
> irb(main):002:0> components = fname.split('/')
> => ["home", "foo", "bar"]
> irb(main):003:0> [components.shift, components.join('/')]
> => ["home", "foo/bar"]

That would be safer if fname were a Pathname.

But then, would split only split off the last path part? Or the first?

If the last, how could we roll many splits up, then pop the first?

--
Phlip

Trans

7/27/2008 6:48:00 PM

0

Bill Walton wrote:
> Hi Trans,
>
> Trans wrote:
>
>> I need to split a path by head/*tail.
>>
>> Ex.
>>
>> File.head_tail_split('home/foo/bar') #=> [ 'home', 'foo/bar' ]
>>
>
> You could do like this.
>
> def head_tail_split(fname)
> components = fname.split('/')
> [components.shirt, components.join('/')]
> end
>
> irb(main):001:0> fname = 'home/foo/bar'
> => "home/foo/bar"
> irb(main):002:0> components = fname.split('/')
> => ["home", "foo", "bar"]
> irb(main):003:0> [components.shift, components.join('/')]
> => ["home", "foo/bar"]

That's basically were I ended up too, but using David's File::Separator
suggestion.

However you made me think it would be helpful for Pathname to have:

class Pathname
def to_a
to_s.split(File::Separator) # better definition ?
end
end

The funny thing is that reminds me of a rewrite of Pathname I did a
while back that used an internal array instead of a string to store the
path. It was ~20% faster than the current lib. But alas, no one cared :(

T.
--
Posted via http://www.ruby-....

ara.t.howard

7/28/2008 3:27:00 AM

0


On Jul 26, 2008, at 1:54 PM, Trans wrote:

> I need to split a path by head/*tail.
>
> Ex.
>
> File.head_tail_split('home/foo/bar') #=> [ 'home', 'foo/bar' ]
>
> Sure, I can write a clumsy loop like the following:
>
> def File.head_tail_split(fname)
> s = fname
> t = []
> h = nil
> until s == '.'
> t << h
> s, h = *split(s)
> end
> return h, File.join(*t.compact)
> end
>
> But I'm betting there's a better way. Or maybe there's already an easy
> way I'm overlooking



cfp:~ > cat a.rb
path = File.join 'a', 'b', 'c'

head, tail = path.split( File::SEPARATOR, 2 )

p :head => head, :tail => tail



cfp:~ > ruby a.rb
{:tail=>"b/c", :head=>"a"}




a @ http://codeforp...
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama




Bill Walton

7/28/2008 3:29:00 AM

0

Hi Phlip,
Phlip wrote:

> That would be safer if fname were a Pathname.

Not sure what you mean here by 'safer'. Say more?

Best regards,
Bill

Martin DeMello

7/28/2008 5:48:00 AM

0

On Sun, Jul 27, 2008 at 11:47 AM, Thomas Sawyer <transfire@gmail.com> wrote:
>> irb(main):002:0> components = fname.split('/')
>> => ["home", "foo", "bar"]
>> irb(main):003:0> [components.shift, components.join('/')]
>> => ["home", "foo/bar"]
>
> That's basically were I ended up too, but using David's File::Separator
> suggestion.

Don't forget the second argument to split - it'd be handy here.

first, rest = fname.split(File::Separator, 2)

though you'd probably have to thrown in an
if fname.index(File::Separator) == 0 then fname = fname[1..-1]
first

martin

Phlip

7/28/2008 11:35:00 AM

0

Bill Walton wrote:

>> That would be safer if fname were a Pathname.
>
> Not sure what you mean here by 'safer'. Say more?

At work we just finished a rewrite of a system that generously manipulated
folders, paths, and files. The old system originally used only strings, and
string surgery, to manipulate paths. (The old system was also very shabby and
patched up; it started as a one-shot script with no structure, etc.)

In the new system we follow a simple rule: If it's a filename, relative path, or
absolute path of any kind, it's a Pathname. This allows us to stay within the
Pathname feature set, and manipulate paths without any string surgery. The
result is much more typesafe.

In theory, Pathnames would be safer if you needed to support \ path delimiters,
and if you needed to support paths with embedded \ or / characters. We are very
good string surgeons, so we never had those problems.

--
Phlip