LISP: formatting the output of read-line while reading a game board from a file - lisp

I am trying to read the board from a text file, but while printing it is also printing the newline and inverted commas as:
(with-open-file (stream "brd1.txt")
(do ((line (read-line stream nil)
(read-line stream nil)))
((null line))
(print line)))
"+ + +^M"
" 3 3 ^M"
"+ + +^M"
" ^M"
"+ + +"
NIL
I am new to LISP. Could somebody help me to format these lines to print the exact board as:
+ + +
3 3
+ + +
+ + +

Input
Apparently you're trying to feed a DOS text file with CRLF-delimited lines to a Lisp implementation that assumes the lines to be LF-delimited in the Unix fashion. Note that read-line strips the newlines, so in our case LF's are stripped, but CR's are treated as ordinary characters and thus remain in the string.
Newlines are platform specific and hence implementation dependent in Lisp. What's more, it seems that neither asdf nor asdf-encodings address this issue. The way I see it you have the following options:
trim the CR's manually e. g. like this:
(string-right-trim '(\#Return) line)
use one of asdf's functions slurp-stream-string and slurp-stream-lines;
use some implementation specific mechanism to specify the encoding;
convert your text file to the Unix format.
Output
As already noted, PRINT is actually a human-readable serialisation. There is a bunch of printing functions on CLHS's page for WRITE and, of course, FORMAT. In order to output a string you can also use WRITE-STRING (without appending a newline) or WRITE-LINE (with a newline).
UPD
Actually UIOP (not ASDF!) exports the utility function UIOP:STRIPLN, which does the following, according to its docstring:
"Strip a string X from any ending CR, LF or CRLF.
Return two values, the stripped string and the ending that was stripped,
or the original value and NIL if no stripping took place.
Since our STRCAT accepts NIL as empty string designator,
the two results passed to STRCAT always reconstitute the original string"

As you can see from the documentation, print "produces output suitable for input to read". Use format instead:
(format t "~a" line)

Related

TXR: How to combine all lines where the following line begins with a tab?

I am trying to parse the text output of a shell command using txr.
The text output uses a tab indented line following it to continue the current line (not literal \t characters as I show below). Note that on other variable assignment lines (that don't represent extended length values), there are leading spaces in the input.
Variable Group: 1
variable = the value of the variable
long_variable = the value of the long variable
\tspans across multiple lines
really_long_variable = this variable extends
\tacross more than two lines, but it
\tis unclear how many lines it will end up extending
\tacross ahead of time
Variable Group: 2
variable = the value of the variable in group 2
long_variable = this variable might not be that long
really_long_variable = neither might this one!
How might I capture these using the txr pattern language? I know about the #(freeform) directive and it's optional numeric argument to treat the next n lines as one big line. Thus, it seems to me the right approach would be something like:
#(collect)
Variable Group: #i
variable = #value
#(freeform 2)
long_variable = #long_value
#(set long_value #(regsub #/[\t ]+/ "" long_value))
#(freeform (count-next-lines-starting-with-tab))
really_long_variable = #really_long_value
#(set really_long_value #(regsub #/[\t ]+/ "" really_long_value))
#(end)
However, it's not clear to me how I might write the count-next-lines-starting-with-tab procedure with TXR lisp. On the other hand, maybe there is another better way I could approach this problem. Could you provide any suggestions?
Thanks in advance!
Let's apply the KISS principle; we don't need to bring in #(freeform). Instead we can separately capture the main line and the continuation lines for the (potentially) multi-line variables. Then, intelligently combine them with #(merge):
#(collect)
Variable Group: #i
variable = #value
long_variable = #l_head
# (collect :gap 0 :vars (l_cont))
#l_cont
# (end)
really_long_variable = #rl_head
# (collect :gap 0 :vars (rl_cont))
#rl_cont
# (end)
# (merge long_variable l_head l_cont)
# (merge really_long_variable rl_head rl_cont)
#(end)
Note that the big indentations in the above are supposed to be literal tabs. Instead of literal tabs, we can encode tabs using #\t.
Test run on the real data with \t replaced by tabs:
$ txr -Bl new.txr data
(i "1" "2")
(value "the value of the variable" "the value of the variable in group 2")
(l_head "the value of the long variable" "this variable might not be that long")(l_cont ("spans across multiple lines") nil)
(rl_head "this variable extends" "neither might this one!")
(rl_cont ("across more than two lines, but it" "is unclear how many lines it will end up extending"
"across ahead of time") nil)
(long_variable ("the value of the long variable" "spans across multiple lines")
("this variable might not be that long"))
(really_long_variable ("this variable extends" "across more than two lines, but it"
"is unclear how many lines it will end up extending" "across ahead of time")
("neither might this one!"))
We use a strict collect with :vars for the continuation lines, so that the variable is bound (to nil) even if nothing is collected. :gap 0 prevents these inner collects from scanning across lines that don't start with tabs: another strictness measure.
#(merge) has "special" semantics for combining lists of strings that haver different nesting levels; it's perfect for assembling data from different levels of collection and is basically tailor made for this kind of thing. This problem is very similar to extracting HTTP, Usenet or e-mail headers, which can have continuation lines.
On the topic of how to write a Lisp function to look ahead in the data, the most important aspect is how to get a handle on the data at the current position. The TXR pattern matching works by backtracking over a lazy list of strings (lines/records). We can use the #(data) directive to capture the list pointer at the given input position. Then we can just treat that as a list:
#(data here)
#(bind tab-start-lines #(length (take-while (f^ #/\t/) here))
Now tab-start-lines has a count of how many lines in the input start with tabs. However, take-while has a termination condition bug, unfortunately; if the following data consists of nothing but one or more tab lines, it misbehaves.⚠ Until TXR 166 is released, this requires a little workaround: (take-while [iff stringp (f^ #/\t/)] here).

read-minibuffer function input string with " Punctuation

I write emacs lisp code as follows:
#!/usr/bin/emacs --script
(setq input (read-minibuffer "please input your name:") )
(message "%s" input)
and then I use this code to test standard input:
./test.el
please input your name:hello
hello
this is ok for the first test. But when I put string hello,world to standard input, it occurs error:
please input your name:hello,world
Trailing garbage following expression
And then I put string "hello,world" to standard input, it passed:
please input your name:"hello,world"
hello,world
Then I want to know, how should I do that can get the input string without "
punctuation. I just want to input hello,world, rather then "hello,world".
Thanks
The function read-minibuffer expects the user to input a Lisp object. If you enter hello, it returns a symbol, and if you enter "hello,world", it returns a string.
You probably want the function read-from-minibuffer instead. It returns what the user entered as a string, without trying to interpret it in any way.

How can I get a substring of a string in Emacs Lisp?

When I have a string like "Test.m", how can I get just the substring "Test" from that via elisp? I'm trying to use this in my .emacs file.
One way is to use substring (or substring-no-properties):
(substring "Test.m" 0 -2) => "Test"
(substring STRING FROM &optional TO )
Return a new string whose contents are a substring of STRING. The
returned string consists of the characters between index FROM
(inclusive) and index TO (exclusive) of STRING. FROM and TO are
zero-indexed: 0 means the first character of STRING. Negative values
are counted from the end of STRING. If TO is nil, the substring runs
to the end of STRING.
Stefan's answer is idiomatic, when you just need a filename without extension. However, if you manipulate files and filepaths heavily in your code, i recommend installing Johan Andersson's f.el file and directory API, because it provides many functions absent in Emacs with a consistent API. Check out functions f-base and f-no-ext:
(f-base "~/doc/index.org") ; => "index"
(f-no-ext "~/doc/index.org") ; => "~/doc/index"
If, instead, you work with strings often, install Magnar Sveen's s.el for the same reasons. You might be interested in s-chop-suffix:
(s-chop-suffix ".org" "~/doc/index.org") ; => "~/doc/index"
For generic substring retrieval use dkim's answer.
In your particular case, you might like to use file-name-sans-extension.
Probably the most flexible option (although it's not clear if you need flexibility) would be to use replace-regexp-in-string:
See C-hf replace-regexp-in-string RET
e.g.:
(replace-regexp-in-string "\\..*" "" "Test.m")

Formatting fprintf

I have a bit of Matlab code and I am trying to export some string and create a tab-delimitted text file from it. I think fprintf performs similarly in C (if not please edit my tag). I believe my issue is with my format string. Basically I have 7 strings that I want separated by tabs and then a newline character. please note that "fid" is a full path. I am looping this in a for loop so lines are being appended each pass and the file is built.
ImgData = strcat(ImgData, fid, '\t', imgNumber, '\t', N_std,'\t',S,'\t',N,'\t',SNR,'\t',SNR_dB,'\n');
DataOut = fopen(strcat('Image_F', folderNumber, '_Data.txt'), 'w');
fprintf(DataOut,'%s\t %s\t %s\t %s\t %s\t %s\t %s\n',ImgData);
You may be curious on how this exports. This formats like
fid\tI#\tN_std\tS\tN\tSNR\tSNR_dB\n
in the txt file. As you can tell this isn't tab-delimitted which my major issue. I am having some trouble with the format string. Does anyone know how to reformat it so it prints the tabs and newline?
You're creating a string in ImgData that you then pass as input to fprintf. This reads ImgData into the first %s of the format string, and then adds at least one tab at the end.
What you should do instead is write something like:
`fprintf(DataOut,'%s\t%i\n',imgName,imgNumber)`
which assumes that imgName is a string and imgNumber an integer number. Note that I pass two placeholders (with the %-sign) and two input variables to fprintf.
Use %6.2f print floating point numbers with a total of 6 characters, including 2 after the comma, for SNR, for example.
For easier development, you can drop the first input argument to fprintf, in which case it will print to command line.

Idiomatic way to write Clojure code for repeatedly reading lines from the console?

Recently I was writing a little CLI script which needed to repeatedly read dates from the console (the number of dates to read was calculated and could be different each time). Sample Ruby code to give you the idea:
dates = x.times.collect { print "Enter date: "; Date.parse(gets.chomp) }
Just for the heck of it, I wrote the script in Clojure, and wound up using some rather ugly code with swap! and loop...recur. I'm wondering what the cleanest way to achieve the desired effect in Clojure would be. (Clojure does have dotimes, but it doesn't retain the values returned from evaluating the body... as might be expected from a language which emphasizes pure functional programming.)
read-line returns nil when the end of file is reached. On the console that is when you press CTRL-d (CTRL-z on Windows).
You could use this code to take advantage of this:
(doseq [line (repeatedly read-line) :while line]
(do-something-with line))
If you must read a fixed number of lines you can use:
(repeatedly n read-line)
If your goal is to end up with a sequence of exactly x dates entered by user then:
(for [line (repeatedly x read-line)] (DateFormat/parse line))
or using map:
(map DateFormat/parse (repeatedly x read-line))
Beware of lazy sequences in Clojure: user will be asked to enter more dates as they are needed. If your goal is for user to enter all dates at once (say at startup) then use doall:
(map DateFormat/parse (doall (repeatedly x read-line)))
This will read all dates at once, but will parse them lazily still, so date format validation could fail much later in your program. You can move doall one level up to parse promptly as well:
(doall (map DateFormat/parse (repeatedly x read-line)))
And you can use a helper function to read line with prompt:
(defn read-line-with-prompt [prompt]
(print prompt)
(read-line))
Then replace read-line with either:
#(read-line-with-prompt "Enter date: ")
or
(partial read-line-with-prompt "Enter date: ")
You can do something like this:
(defn read-dates [n]
(doall (for [_ (range n)] (java.util.Date/parse (read-line)))))
(def my-dates (read-dates 5)) ;Read 5 dates from console