Parsing a string containing "\" in Racket - windows

I am trying to extract tokens from a Windows path string that contains "\".
I have tried string-split and string->list, but one of the path elements starts with a "d", so I get a "read: unknown escape sequence \d in string" error.
Edit: The paths have the form: "\\aaaa\bbbb\cccc\dddd\eeee....". I need to extract, for example, the "eeee" part. The "string->" functions choke on the "dddd" element, with the above error. On Windows 7, Racket 5.3.3. For example : (string-split path), (string->list path)

Backslash is used as escape in strings. If you do (read-line) and enter one backslash the result is "\\".
For hardcoded strings to test your programs you need to write like this "\\\\aaaa\\bbbb\\..."

Related

Can I pass a json object as value for a cli flag in go?

I am using urfave/cli for my go program and I would like to have a cli flag that reads a json value like this one:
{"name":"foo","surname":"var"}
I am currently reading that variable as a cli.StringFlag which returns a string. Then, I was planning to json.Unmarshall it but it does not work. The problem is that the returned string by the cli library is like this:
[{name foo} {surname var}]
which is not a json anymore.
Is there a way to achieve this? Note that if it returned a simple map, that would work too
for Linux, try to pass the paramaters with shell escape
#!/bin/bash
echo "{\"name\":\"foo\",\"surname\":\"var\"}"
in go program, just marshal this string parameter
The issue is that the shell (bash, ksh, csh, zsh, ...) interprets
{"name":"foo","surname":"var"}
as a sequence of bareword and quoted word tokens:
Token Type
Value
bareword
{
quoted word
name
bareword
:
quoted word
foo
bareword
,
quoted word
surname
bareword
:
quoted word
var
bare word
}
As it happens, a comma (,) is a shell operator, used for arithmetic, and that essentially gets discarded (at least in zsh, what I use).
The whole is then spliced together to get
name:foo surname:var
You can see this in action by opening your shell and executing the command
echo {"name":"foo","surname":"var"}
If, however, you quote your JSON document with single quotes ('):
echo '{"name":"foo","surname":"var"}'
You'll get what you might expect:
{"name":"foo","surname":"var"}
Note, however, that this will fail if the text in your JSON document contains a literal apostrophe/single quote (', U+0027), so you'd want to replace all such occurrences within the JSON document with \, to escape them.

How to obtain basename in ruby from the given file path in unix or windows format?

I need to parse a basename in ruby a from file path which I get as input. Unix format works fine on Linux.
File.basename("/tmp/text.txt")
return "text.txt".
However, when I get input in windows format:
File.basename("C:\Users\john\note.txt")
or
File.basename("C:\\Users\\john\\note.txt")
"C:Usersjohn\note.txt" is the output (note that \n is a new line there), but I didn't get "note.txt".
Is there some nice solution in ruby/rails?
Solution:
"C:\\test\\note.txt".split(/\\|\//).last
=> "note.txt"
"/tmp/test/note.txt".split(/\\|\//).last
=> "note.txt"
If the Linux file name doesn't contain \, it will work.
Try pathname:
require 'pathname'
Pathname.new('C:\Users\john\note.txt').basename
# => #<Pathname:note.txt>
Pathname docs
Ref How to get filename without extension from file path in Ruby
I'm not convinced that you have a problem with your code. I think you have a problem with your test.
Ruby also uses the backslash character for escape sequences in strings, so when you type the String literal "C:\Users\john\note.txt", Ruby sees the first two backslashes as invalid escape sequences, and so ignores the escape character. \n refers to a newline. So, to Ruby, this literal is the same as "C:Usersjohn\note.txt". There aren't any file separators in that sequence, since \n is a newline, not a backslash followed by the letter n, so File.basename just returns it as it receives it.
If you ask for user input in either a graphical user interface (GUI) or command line interface (CLI), the user entering input needn't worry about Ruby String escape sequences; those only matter for String literals directly in the code. Try it! Type gets into IRB or Pry, and type or copy a file path, and press Enter, and see how Ruby displays it as a String literal.
On Windows, Ruby accepts paths given using both "/" (File::SEPARATOR) and "\\" (File::ALT_SEPARATOR), so you don't need to worry about conversion unless you are displaying it to the user.
Backslashes, while how Windows expresses things, are just a giant nuisance. Within a double-quoted string they have special meaning so you either need to do:
File.basename("C:\\Users\\john\\note.txt")
Or use single quotes that avoid the issue:
File.basename('C:\Users\john\note.txt')
Or use regular slashes which aren't impacted:
File.basename("C:/Users/john/note.txt")
Where Ruby does the mapping for you to the platform-specific path separator.

Why does File.dirname returns a period when I expect a path?

I am trying to get the directory of a file on a Windows box using File.dirname. I get the file ("file1" below) from the Windows box and return it to my the Mac OS X box that the script is run on.
file1 = "C:\Administrator\proj1\testFile.txt" below is to simplify my example, however, to make it more clear, I am getting this value from a remote box and returning it to my development box:
file1 = "C:\Administrator\proj1\testFile.txt"
path = "#{File.dirname(file1)}"
puts "#{path}"
>> .
I am confused on why it would return '.'. I saw on ruby-doc.org that File.dirname says the following:
"Returns all components of the filename given in file_name except the last one. The filename can be formed using both File::SEPARATOR and File::ALT_SEPARETOR as the separator when File::ALT_SEPARATOR is not nil."
I did a puts on File::SEPARATOR and File::ALT_SEPARATOR and got the following:
File::SEPARATOR >> /
File::ALT_SEPARATOR >>
I assumed it was because "\" wasn't a valid file separator. So I set File::ALT_SEPARATOR to "\". However, even after that, I still got the same value when I puts path.
I tried using File.realdirpath and this was the result:
file1 = "C:\Administrator\proj1\testFile.txt"
path = "#{File.realdirpath(file1)}"
puts "{path}"
>> /Users/me/myProject/C:\Administrator\proj1\testFile.txt
It seemed to add the path from where I called the Ruby script and appended the full path (including the file name). Seems to be odd behavior.
Any ideas, comments or suggestions would be great.
The problem is that when you declare file1, those backslashes define escape characters. Notice the return:
file1 = "C:\Administrator\proj1\testFile.txt"
=> "C:Administratorproj1\testFile.txt"
If you want to store a filepath in a string, you either need to use forward slashes or double backslashes (to escape the escape character):
file1 = "C:\\Administrator\\proj1\\testFile.txt"
file1 = "C:/Administrator/proj1/testFile.txt"
Okay, I was able to duplicate this problem as well.
As #fbonetti pointed out, you have to enclose your directory with single quotes to keep ruby from interpreting the backslashes as escapes, so start with that...
>> file1='C:\Administrator\proj1\testFile.txt'
=> "C:\\Administrator\\proj1\\testFile.txt"
Then, passing file1 through gsub to 'normalize' the slashes, gives you the results you're expecting.
>> File.dirname(file1.gsub('\\', '/'))
=> "C:/Administrator/proj1"
Of course, you could always reverse the gsub if you needed them to be backslashes again.
>> File.dirname(file1.gsub('\\', '/')).gsub('/', '\\')
=> "C:\\Administrator\\proj1"
I figured it out. It was an issue with the version of Ruby I was using. I was using ruby 1.9.3 and then I switched to jruby 1.7.3 and it works correctly now.
Ruby's IO documentation is of great help when dealing with different OS path separators. From the 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"
Our examples here will use the Unix-style forward slashes; File::ALT_SEPARATOR can be used to get the platform-specific separator character.
So, in other words, you don't need to hassle with backslashes, and whether you need to use single or double-quotes. Keep it simple, and use forward-slashes and let Ruby worry about it. That way your code is portable across *nix/Mac OS and Windows.
Beyond that, it looks like there's a real need to learn how character escaping works in double-quoted strings vs. single-quoted strings. This is from "Programming Ruby":
Ruby provides a number of mechanisms for creating literal strings. Each generates objects of type String. The different mechanisms vary in terms of how a string is delimited and how much substitution is done on the literal's content.
Single-quoted string literals (' stuff ' and %q/stuff/) undergo the least substitution. Both convert the sequence into a single backslash, and the form with single quotes converts \' into a single quote.
'hello' » hello
'a backslash \'\\\'' » a backslash '\'
%q/simple string/ » simple string
%q(nesting (really) works) » nesting (really) works
%q no_blanks_here ; » no_blanks_here
Double-quoted strings ("stuff", %Q/stuff/, and %/stuff/) undergo additional substitutions, shown in Table 18.2 on page 203.
Substitutions in double-quoted strings
\\a Bell/alert (0x07) \\nnn Octal nnn
\\b Backspace (0x08) \\xnn Hex nn
\\e Escape (0x1b) \\cx Control-x
\\f Formfeed (0x0c) \\C-x Control-x
\\n Newline (0x0a) \\M-x Meta-x
\\r Return (0x0d) \\M-\\C-x Meta-control-x
\\s Space (0x20) \\x x
\\t Tab (0x09) #{expr} Value of expr
\\v Vertical tab (0x0b)
a = 123
"\123mile" » Smile
"Say \"Hello\"" » Say "Hello"
%Q!"I said 'nuts'," I said! » "I said 'nuts'," I said
%Q{Try #{a + 1}, not #{a - 1}} » Try 124, not 122
%<Try #{a + 1}, not #{a - 1}> » Try 124, not 122
"Try #{a + 1}, not #{a - 1}" » Try 124, not 122

Strip all spaces from a variable and append to another variable if not blank

I'm using make in Windows and I need to manipulate some variables to create a filename. I have a base filename and an optional part to append. If the optional part is appended an underscore should be inserted between two parts. The optional part is being read in from a file and contains 5 characters (spaces or alphanumeric).
This is what I expected to work:
OPTIONAL_NAME=" "
BASE_NAME=myfile
STRIPPED_OPTIONAL_NAME=$(strip $(OPTIONAL_NAME))
ifeq ("$(STRIPPED_OPTIONAL_NAME)","")
FULL_NAME=$(BASE_NAME)
else
FULL_NAME=$(BASE_NAME)_$(STRIPPED_OPTIONAL_NAME)
endif
OPTIONAL_NAME could have the following values:
OPTIONAL_NAME=" "
OPTIONAL_NAME="ABCDE"
OPTIONAL_NAME="A "
OPTIONAL_NAME=" A "
OPTIONAL_NAME=" A"
The value of OPTIONAL_NAME has quotes around it due to the way it is being imported (see my previous question - Read a value from a file into a variable).
The problem with the result is that strip seems to reduce multiple spaces to single spaces, but not actually remove leading or trailing spaces.
I've tried using this to strip the spaces:
space:=
space+=
STRIPPED_OPTIONAL_NAME=$(subst $(space),,$(OPTIONAL_NAME))
This does remove the spaces, but I struggle to check for an empty string.
Thanks
Stephen
You should not put the variable in the comparison in quotation marks. Try this instead:
ifeq ($(STRIPPED_OPTIONAL_NAME),"")
The above checks for empty strings.
Or
ifeq ($(STRIPPED_OPTIONAL_NAME)," ")
to check for single space.

Ruby string with quotes for shell command args?

Hi I need to create string like this:
drawtext="fontfile=/Users/stpn/Documents/Video_Experiments/fonts/Trebuchet_MS.ttf:text='content':fontsize=100:fontcolor=red:y=h/2"
I want to do something like
str = Q%[drawtext="fontfile=/Users/stpn/Documents/Video_Experiments/fonts/Trebuchet_MS.ttf:text='content':fontsize=100:fontcolor=red:y=h/2"]
I am getting this:
=> "drawtext=\"fontfile=/Users/stpn/Documents/Video_Experiments/fonts/Trebuchet_MS.ttf:text='content':fontsize=100:fontcolor=red:y=h/2\""
The escape characters after equals sign in drawtext=" is what I want to get rid of.. How to achieve that?
The string is to be used in a command line args.
Like many languages, Ruby needs a way of delimiting a quoted quote, and the enclosing quotes.
What you're seeing is the escape character which is a way of saying literal quote instead of syntactic quote:
foo = 'test="test"'
# => "test=\"test\""
The escape character is only there because double-quotes are used by default when inspecting a string. It's stored internally as a single character, of course. You may also see these in other circumstances such as a CR+LF delimited file line:
"example_line\r\n"
The \r and \n here correspond with carriage-return and line-feed characters. There's several of these characters defined in ANSI C that have carried over into many languages including Ruby and JavaScript.
When you output a string those escape characters are not displayed:
puts foo
test="test"

Resources