Jon.Stromer.Galley Jon.Stromer.Galley - 7 months ago 19
Ruby Question

How to list files given path with poorly escaped Windows separator

I'm attempting to do this:

Dir["c:\temp\*.*"]


but that is failing. I understand why, but I seem to lack the Ruby prowess to work around it.

I am given the path in a variable and otherwise have no control over it. Nor do I know the contents ahead of time.

Is there a way to make Dir function with double quoted strings that are poorly escaped? Alternatively, how does one take a variable with the apparent contents

"c:\temp\*.*"


and convert it into

'c:/temp/*.*'


This problem at the core seems to be how to potentially escape a string that should have been escaped but now is not.

The end result is I am not able to use the given string to do this as conceptually simple as
puts()
or
Dir[]
.

If given
'c:\temp\*.*'
then I have no problem. I can fix that:

foo = 'c:\temp\*.*'.gsub('\\', '/')


If given
"c:\\\\temp\\\\*.*"
then I have no problem. I can fix that:

foo = "c:\\temp\\*.*".gsub("\\", "/")


However, I am passed neither of those, but rather
"c:\\temp\\*.*"
. This string contains a TAB and a second undefined escape. It is this that I can't fix in a general way.

Even if I knew the contents ahead of time I am stumped on how to properly escape and transform this. I should add that I am not a ruby programmer at the moment so maybe there is some simple method to deal with this that I am not aware of.

I tried a bunch of stuff like:

"c:\temp\*.*".gsub("\t", "/t")


which gets me part of the way, but since the actual contents of the string are not known to me ahead of time this is a little wonky. Further, if the escape character is not valid as in
\\*
then I am also in a jam. So this also fails:

"c:\temp\*.*".gsub("\t", "/t").gsub("\*", "/*")

Answer

Is there a way to make Dir function with double quoted strings that are poorly escaped?

No.

Garbage in, garbage out. There is no Rumpelstiltskin routine that returns gold when given trash.

Ruby auto-converts forward-slashes in filenames/paths to reverse-slashes when running on Windows. Simply make it a habit of using forward, *nix-style, slashes and you'll be fine.

From the IO documentation:

Ruby will convert pathnames between different operating system conventions if possible. For instance, on a Windows system the filename "/gumby/ruby/test.rb" will be opened as "\gumby\ruby\test.rb". When specifying a Windows-style filename in a Ruby string, remember to escape the backslashes:

"c:\\gumby\\ruby\\test.rb"

I don't have "c:\temp" I have "c:\temp" as input

In a properly defined Windows path you should see:

'c:' + '\temp' + '\*.*' # => "c:\\temp\\*.*"

Note that the single-quotes are treating "\t" as an escaped-escape + "t". Your source for the variable is creating the string improperly by using double-quotes:

'c:' + "\temp" + "\*.*" # => "c:\temp*.*"

If you have "\t", you have a TAB character. It's possible to change it to an escaped-T using:

"c:\temp" # => "c:\temp"
"c:\temp"[2] # => "\t"
"c:\temp"[2].ord # => 9

'\t' # => "\\t"

"c:\temp".sub("\t", '\t') # => "c:\\temp"

The next problem is what to do when you have a String containing "*" to convert it to "\*". There's no way to search for "\*" because that's the same as "*" as seen above:

"\*.*" # => "*.*"

But, since "*.*" is a fairly specific "anything" wildcard, maybe simply searching for and replacing that pattern would work:

"c:\temp\*.*".gsub('*.*', '\\*.*') # => "c:\temp\\*.*"

or:

"c:\temp\*.*".gsub('*.*', '/*.*') # => "c:\temp/*.*"

Back to dealing with "\t" and putting it all together... I'd start with:

"c:\temp\*.*".gsub("\t", '\t').gsub('*.*', '/*.*') # => "c:\\temp/*.*"
"c:\temp\*.*".gsub("\t", '/t').gsub('*.*', '/*.*') # => "c:/temp/*.*"

You'll have to figure out what to do if you have something like:

c:/dir/file*.*

where they mean they want all files starting with file. Since you're seeing ambiguous inputs it seems the input routine needs to be more rigorous to not allow reversed-slashes.

Comments