How to read input as a string in Racket?
This code reads input like a line but from a current line. How to read it from a newline.
(let ([x (read-line (current-input-port))]) x) ;read from here
;will read a \newline symbol after we hit 'enter' button
Related
In python you can write this r"c:\data"
How do I the same in lisp? ie I want a reader macro that has the same functionality so I no longer need to escape backslashes in windows paths. I do not want to use forward slashes as plenty of commands in windows dont understand them.
For instance
(defun read-literal-string (stream delimiter arg)
(declare (ignore arg))
(loop for char = (read-char stream nil stream)
when (eq char stream)
do (error "hit end of stream")
until (char= char delimiter)
collect char into chars
finally (return (coerce chars 'string))))
(set-dispatch-macro-character #\# #\" #'read-literal-string)
And now
> #"fo\o"
"fo\\o"
> #"foo\"
"foo\\"
obviously a real version would be more carefully written
I am trying to create an org-table based on the content of a CSV file that uses ";" as a delimiter.
I thought it would be easy to have a source code block to "cat" the content of the file and then pass the result to a function that creates the table, but I got stuck: I can't find a way to use the "results" of the first source code block. The function I know (org-table-convert-region) expects a region to work on and I don't know how to pass the "cat"-ed text as a region.
#+NAME: csvraw
#+BEGIN_SRC sh :results raw
cat afile.csv
#+END_SRC
I'd appreciate your help to generate a code block that produces an org-table out of my csv file, which contains lines like the following:
ID;Region;SubRegion;Area;No
1234;Asia;India;45;2
24251;Europe;Romania;456;67
There is org-table-convert-region (bound to C-c |) which can do the transformation fairly simply. The only trick is to specify ; as the separator. You can do that by invoking it with the proper prefix argument - the doc string says:
(org-table-convert-region BEG0 END0 &optional SEPARATOR)
Convert region to a table.
The region goes from BEG0 to END0, but these borders will be moved
slightly, to make sure a beginning of line in the first line is included.
SEPARATOR specifies the field separator in the lines. It can have the
following values:
(4) Use the comma as a field separator
(16) Use a TAB as field separator
(64) Prompt for a regular expression as field separator
integer When a number, use that many spaces, or a TAB, as field separator
regexp When a regular expression, use it to match the separator
nil When nil, the command tries to be smart and figure out the
separator in the following way:
- when each line contains a TAB, assume TAB-separated material
- when each line contains a comma, assume CSV material
- else, assume one or more SPACE characters as separator.
The (64) value is just three C-u in a row, so the process is as follows:
insert the CSV file with C-x i.
C-x C-x to mark the inserted contents as the active region.
C-u C-u C-u C-c | ; RET
What's even cooler, leaving an empty line in the CSV file between the first line and the rest of the lines, will make the first line a header in the table automatically.
And you can wrap it up in a code block as well:
#+begin_src elisp :var file="/tmp/foo.csv" :results raw
(defun csv-to-table (file)
(with-temp-buffer
(erase-buffer)
(insert-file file)
(org-table-convert-region (point-min) (point-max) ";")
(buffer-string)))
(csv-to-table file)
#+end_src
#+RESULTS:
| a | b | c |
|---+---+---|
| d | e | f |
| g | h | i |
(defun jea-convert-csv-to-org-table (fname)
(interactive "fCSV to convert: ")
(let ((result '("|-\n")))
(with-temp-buffer
(save-excursion (insert-file-contents-literally fname))
(while (and (not (eobp)) (re-search-forward "^\\(.+\\)$" nil t nil))
(push (concat "|" (replace-regexp-in-string ";" "|" (match-string 1)) "|\n")
result))
(push '"|-\n" result))
(concat (seq-mapcat #'identity (reverse result)))))
install the elisp code in your ~/.emacs file and restart emacs. Or, better yet, eval it into existence (CTRL+x, CTRL+e or ALT+x eval-last-sexp).
#+NAME: csvraw
#+BEGIN_SRC elisp :results raw
(jea-convert-csv-to-org-table "/Users/jamesanderson/Downloads/test1.csv")
#+END_SRC
note the change to elisp from sh in the above. here is a gif of it in action:
emacs converting csv to org table
The code is not optimized for large files, and, to be frank, quite quickly thrown together. But, after a tiny bit of testing, seems to work.
I have a file formatted as
abc|<hoge>
a|<foo> b|<foo> c|<foo>
family|<bar> guy|<bar>
a|<foo> comedy|<bar> show|<foo>
action|<hoge>
and want to search search strings by raw (Like "a comedy show" instead of a|<foo> comedy|<bar> show|<foo>) on emacs.
I believe using grep on lisp would be the easiest answer but I have not yet figured out how. Would someone enlighten me?
Well, grep is a separate program (which you could also use). In Emacs, you'd use the function search-forward-regexp, which you can run using either M-x (hold Meta, usually Alt key, and press x) and then type search-forward-regexp and press Return.
You'll then need to key in the regexp to search. Put simply, it seems like you want to ignore |< something >, which in Emacs's variety of regexes is:
|<[a-z]+>
so you might search for e.g.
a|<[a-z]+> comedy|<[a-z]+> show|<[a-z]+>
You can create a Lisp function to convert a string this way, by splitting it on spaces and adding the regex sequences:
(defun find-string-in-funny-file (s) ; Define a function
"Find a string in the file with the |<foo> things in it." ; Document its purpose
(interactive "sString to find: ") ; Accept input if invoked interactively with M-x
(push-mark) ; Save the current location, so `pop-global-mark' can return here
; (usually C-u C-SPC)
(goto-char 0) ; Start at the top of the file
(let ((re (apply #'concat ; join into one string…
(cl-loop
for word in (split-string s " ") ; for each word in `s'
collect (regexp-quote word) ; collect that word, plus
collect "|<[a-z]+> ")))) ; also the regex bits to skip
(search-forward-regexp ; search for the next occurrence
(substring re 0 (- (length re) 2))))) ; after removing the final space from `re'
You can explore what those functions each do in the (online) Emacs Lisp manual; for example, pick from the menu "Help→Describe→Function" or press C-h f (Control+h, then f) and type interactive (RET) for the manual's documentation of that special form.
If you paste the above (defun) into the *scratch* buffer, and position the cursor after the final ) at the end, you can press C-j to evaluate it, and the function will remain with you until you close Emacs.
If you save it in a file named something .el, you can use M-x load-file to load it again in future.
If you then load your "funny" file, and type M-x find-string-in-funny-file, it'll search your file for your string, and leave the cursor on the string. If it's not found, you'll see a message to that effect.
BUGS: The function is less than spectacular style
For example, one line of code in my function
(message "char %c:%d" character count)
will print the counts for each character. For nonprintable chars, such as newline and tab, I want the output looks like:
\n:4
\t:6
instead of printing a newline and tab literally. how can I do that?
You can achieve some of this by let-binding certain variables before printing.
`print-escape-newlines' is a variable defined in `C source code'.
Its value is nil
Documentation:
Non-nil means print newlines in strings as `\n'.
Also print formfeeds as `\f'.
There's also:
print-escape-nonascii
Non-nil means print unibyte non-ASCII chars in strings as \OOO.
print-escape-multibyte
Non-nil means print multibyte characters in strings as \xXXXX.
These all work with prin1, so you can use the %S code in format. e.g.:
(let ((print-escape-newlines t))
(format "%S" "new\nline"))
As suggested by #wvxvw
(defun escaped-print (c)
(if (and (< c ?z)
(> c ?A))
(string c)
(substring (shell-command-to-string (format "printf \"%%q\" \"%s\"" (string c)))
2 -1)))
The substring part is to cut out extra stuff from printf's output. I don't have a great deal of knowledge about this command, so it might not be flawless.
There may be some code somewhere in emacs that can do this for you, but one way would be to write a function that converts the special characters to a string:
(defun print-char(c)
(case c
(?\n "\\n")
(?\t "\\t")
(t (string c))))
Note that you need to use string format rather than character because you're actually writing multiple characters for each special character.
I'm in a class reviewing various languages and we're building a text parser with Lisp. I can get my Lisp program to do lots of different functions with numbers but I'm struggling with text. I want to just peek at the first character in a line to see if it contains a < then do something, but I can't seem to figure out how to go about this simple task. Here's my simple little code so far:
;;;Sets up the y.xml file for use
(setq file (open "c:\\temp\\y.xml"))
;;;Just reads one line at a time, (jkk file)
(defun jkk (x)
(read-line x)
)
;;;Reads the entire file printing each line, (loopfile file)
(defun loopfile (x)
(loop for line = (read-line x nil)
while line do (print line))
)
This next part I tried to combine the loop with an if statement to see if it can find "<" and if so just print that line and skip any others which doesn't work. Any help with doing this really easy task would be greatly appreciated. Never used Lisp or any other functional language before, I'm used to using functions like crazy in my VB and Java projects but I don't have any decent reference materials for Lisp.
After this program is done we don't have to mess with Lisp anymore so I didn't bother to order anything. Trying Google Books.. starting to figure stuff out but this language is and old and tough one!
;;;Reads the entire file printing the line when < is found
(defun loopfile_xml (x)
(loop for line = (read-line x nil)
while line do
(
if(char= line "<")
(print line)
)
)
)
Thanks guys
First, Lisp is not C or Java - it has different indentation conventions:
;;;Sets up the y.xml file for use
(setq file (open "c:\\temp\\y.xml"))
;;;Just reads one line at a time, (jkk file)
(defun jkk (x)
(read-line x))
;;;Reads the entire file printing each line, (loopfile file)
(defun loopfile (x)
(loop for line = (read-line x nil)
while line do (print line)))
and
;;;Reads the entire file printing the line when < is found
(defun loopfile_xml (x)
(loop for line = (read-line x nil)
while line
do (if (char= line "<")
(print line))))
I would also give the variables meaningful names. x is not meaningful.
The function char= works on characters. But both arguments in your code are strings. Strings are not characters. #\< is a character. Strings are also arrays, so you can get the first element of a string using the function aref.
If you want to check if a line is just <, then you can compare the line using the function string= with the string "<".
The documentation:
character comparison: char= and related.
string comparison: string= and related.
accessing array contents with aref.
Lisp is old, but still used and it has a lot of interesting concepts.
To learn Lisp is actually not very tough. You can learn the basics of Lisp in a day. If you already know Java, you may need two or even three days.
To search for a character in a line of text, you could use position, with the char= function as your equality comparator.
Second, you MAY be better off collecting your file into a single string and search there.
Third, there's some excellent reference material available on the web, like the Common Lisp HyperStandard (link) and Peter Seibel's Practical Common Lisp.