CL-PPCRE Unicode Property - common-lisp

I am trying to find a solution to this simple Perl code using the CL-PPCRE Library:
if (/\p{Space}/){
print "This string has some spaces\n";
}
I am a newbie to CL-PPCRE and tried:
(scan "\\p{\\#Space}" "The String has some white spaces")
; I got an error saying property #/Space doesn't exists.
How can I execute an equivalent?

The perl regexp /\p{Space}/ matches more than just " ". cf \p{} docs
One approach is to just use the \s expression:
(cl-ppcre:scan "\\s" (format nil "hi~Cthere" #\return))
To use the whole unicode Space class:
(ql:quickload :cl-unicode)
(cl-ppcre:scan "\\p{Space}" (format nil "hi~Cthere" #\return))
See Unicode properties in the CL-PPCRE docs.

The cl-ppcre library does not require you (at least for space) to use any special constant.
(if (cl-ppcre:scan " " "alle meine entchen")
(FORMAT T "Does have spaces~%")
(FORMAT T "Does not have spaces~%"))
> Does have spaces
(if (cl-ppcre:scan " " "allemeineentchen")
(FORMAT T "Does have spaces~%")
(FORMAT T "Does not have spaces~%"))
> Does not have spaces
will do the trick.

Related

Convert input string into Morse Code with Clojure

I am trying to develop a converter that takes an input string and converts it into morse code through a Morse Library map, while also respecting functional programming rules. Sorry for any clarification issues, I am new to Stack Overflow
(ns clojureassignment.core
(:gen-class))
(require '[clojure.string :as str])
;this function is where the converter is developed
(defn morse->ASCI
[x]
(def morse_Library {:A ".-":B "-...":C "-.-.":D "-..":E ".":F "..-.":G "--.":H "...."
:I "..":J ".---"
:K "-.-":L ".-..":M "--" :N "-.":O "---":P ".--.":Q "--.-":R ".-."
:S "...":T "-":U "..-":V "...-":W ".--":X "-..-":Y "-.--":Z "--.."
:0 "-----":1 ".----":2 "..---":3 "...--":4 "....-":5 "....."
:6 "-....":7 "--...":8 "---..":9 "----."})
(let [stringVector (str/upper-case(seq x))] ;divide the string into a sequence of characters
;trying to create iteration of the input where it checks if its value is found in the morse library
(doseq [[stringVector] (morse_Library)]
(if (= stringVector (morse_Library)
(do (println(str (key morse_Library))))
(do (println("characters not found"))))
)))
(print (str/upper-case stringVector))
)
(defn -main
[& args]
(println "ASCII to Morse Converter.")
(println "Make sure to include whitespaces after each ASCII character. Add String")
(def stringInput (read-line))
(println stringInput )
(morse->ASCI stringInput)
)
(-main)
I tried to create a "doseq" iteration where it checks if the value is found in the map.
Good things:
using a map for your morse translation; maps are also functions and
make it easy to write a transformation like this
Not so good things:
don't def inside other def:s - it's used to define namespace
global things and it is not like var or auto or whatever you
know from other languages
don't use keywords as map keys, if you don't plan to use them like
that; Clojure takes pretty much anything as key. So in your case
use chars
don't seq and then upper-case - wrong order - this will give you
the .toString() from a sequence of characters otherwise
don't name things all the same (stringVector)
doseq is for side-effects; you don't want your morse-code function
to do side-effects (you maybe want to print it later); in functional
programming you shift your side-effects to the edges - this way your
code becomes easier to test and reason about
you pretty much never need :gen-class
use the correct way to require in the
namespace
Clojure prefers snake-case over camelCase
(random rant: if you are using tutorialpoint (I assume this from several
things going wrong here and having them seen there) to learn Clojure: do
yourself a favour and look for another resource; as of now they don't
teach idiomatic Clojure!
Make your transformation a pure function:
upper-case the input
make a seq from it (this now is a sequence of chars) - but you don't
actually have to do this, because the next step will take care of it
map the look-up-table with your designated fallback over each char
join the result
This will look something like this:
(def morse {\A ".-" ,,, })
(->> input
(str/upper-case)
(map #(morse % "???"))
(str/join))
;; preparation of morse map
(ns morse
(:require [clojure.string :as str]))
;; I stole morse dictionary from some python code in:
;; https://www.geeksforgeeks.org/morse-code-translator-python/
(def s "{ 'A':'.-', 'B':'-...',
                    'C':'-.-.', 'D':'-..', 'E':'.',
                    'F':'..-.', 'G':'--.', 'H':'....',
                    'I':'..', 'J':'.---', 'K':'-.-',
                    'L':'.-..', 'M':'--', 'N':'-.',
                    'O':'---', 'P':'.--.', 'Q':'--.-',
                    'R':'.-.', 'S':'...', 'T':'-',
                    'U':'..-', 'V':'...-', 'W':'.--',
                    'X':'-..-', 'Y':'-.--', 'Z':'--..',
                    '1':'.----', '2':'..---', '3':'...--',
                    '4':'....-', '5':'.....', '6':'-....',
                    '7':'--...', '8':'---..', '9':'----.',
                    '0':'-----', ', ':'--..--', '.':'.-.-.-',
                    '?':'..--..', '/':'-..-.', '-':'-....-',
                    '(':'-.--.', ')':'-.--.-'}")
;; and transformed it using clojure to a clojure map:
(def m (read-string (str/replace
(str/replace
(str/replace
(str/replace s
"\n" "")
"                    " " ")
":" " ")
"'" "\"")))
;; now `m` contains the string-to-morse map
The actual answer starts here:
;; convert any text string to a morse string:
(defn string-to-morse [s]
(str/join " "
(map #(get m (str/upper-case %)) (str/split s #""))))
;; and this function can transform the output back to text:
(defn morse-to-string [morse-string]
(let [ms (zipmap (vals m) (keys m))]
(str/join (map #(get (zipmap (vals m) (keys m)) % " ")
(str/split morse-string #" ")))))

Backquote symbol list ending in period

I'm curious if there is a way to end a backquoted symbol list with a period following a comma inserted value.
Here is the sample code:
(defparameter *things* '(book pencil shoe))
(defun inspect-item (item things)
(if (member item things)
`(you pick up the ,item and yeet it out the window.)
`(only realize the truth... there is no ,item.)))
This will succeed (print (inspect-item 'book *things*)) and it produces the symbol list (YOU PICK UP THE BOOK AND YEET IT OUT THE WINDOW.). I assume in this case that the period is part of the symbol WINDOW. (as confirmed using the last function).
However, this will fail (print (inspect-item 'spoon *things*)) claiming that variable ITEM. has no value (Because it thinks the name is item.). Leaving a space between item and the period gives the error illegal end of dotted list which I assume is because it is assuming I'm using dotted list syntax.
Is there any way to get it to produce the symbol I want at the end (BOOK.)?
Possible requirements for a solution
You need to create a new symbol based on an old one:
the same name, with a . appended
probably in the same package
Period as a symbol
Note that you can write a symbol with the period as a name using an escaped symbol: |.| or \..
CL-USER 17 > (let ((item 'foobar))
`(only realize the truth... there is no ,item \.))
(ONLY REALIZE THE TRUTH... THERE IS NO FOOBAR \.)
princ prints without escape characters:
CL-USER 18 > (princ '(ONLY REALIZE THE TRUTH... THERE IS NO FOOBAR \.))
(ONLY REALIZE THE TRUTH... THERE IS NO FOOBAR .) ; <- printed output
(ONLY REALIZE THE TRUTH... THERE IS NO FOOBAR \.) ; <- REPL value
Solution
CL-USER 19 > (defun add-suffix (symbol suffix)
(intern (concatenate 'string
(symbol-name symbol)
(symbol-name suffix))
(symbol-package symbol)))
ADD-SUFFIX
CL-USER 20 > (let ((item 'tree))
`(we went to the ,(add-suffix item '|.|)))
(WE WENT TO THE TREE.)
It can also be useful to use the flexibility of format instead of using concatenate.
CL-USER 22 > (defun add-suffix (symbol suffix)
(intern (format nil "~a~a" symbol suffix)
(symbol-package symbol)))
ADD-SUFFIX
I think that the real problem lies in the attempt to produce text just as the printed representation of a list of symbols. Those are completely different things. The only reason to do it like this could be as some kind of exercise. There are a number of introductory texts that do that kind of thing.
Instead, I'd advise to actually produce text, i. e. strings. You might use the format function that is quite flexible for inserting variable things:
(defparameter *things* '("book" "pencil" "shoe"))
(defun inspect-item (item things)
(if (member item things :test #'string-equal)
(format nil
"You pick up the ~a and yeet it out the window."
item)
(format nil
"Only realize the truth… there is no ~a."
item)))
I partly agree with Svante that turning lists of symbols into text is often the wrong thing. On the other hand things like parsers &c often want to think in terms of symbols rather than strings as symbols have nice properties like (eq a b) working the way you would hope.
That being said, here's an alternative approach: create a list of words and then have a function which turns them into a string representing a sentence, adding appropriate punctuation and capitalization.
(defparameter *things* '(book pencil shoe))
(defun inspect-item (item things)
(sentencify (if (member item things)
`(you pick up the ,item and yeet it out the window)
`(only realize the truth... there is no ,item))))
(defun sentencify (slist &key (question nil))
(format nil "~{~A~^ ~}~A"
(loop for first = t then nil
for w in slist
for ws = (typecase w
(symbol (symbol-name w))
(string w)
(t w))
collect (typecase ws
(string (if first
(string-capitalize ws)
(string-downcase ws)))
(t ws)))
(if question "?" ".")))
And now:
> (inspect-item 'book *things*)
"You pick up the book and yeet it out the window."
> (inspect-item 'bok *things*)
"Only realize the truth... there is no bok."
> (inspect-item '(x . y) *things*)
"Only realize the truth... there is no (x . y).

How to make """this text""" which is in Python, in Common Lisp?

Python has:
"""
line1
line2
line3
"""
How can I do this in Common Lisp?
This is just a regular string:
"
line1
line2
line3
"
You need to escape internal double quotes characters, though.
If you don't want to escape quotes, then you have to change the readtable. In fact, you could easily have the behavior you want (and more) by using the cl-interpol library, which defines a custom syntax for strings, notably different kind of outer delimiters.
CL-USER> (ql:quickload :cl-interpol)
...
CL-USER> (interpol:enable-interpol-syntax)
; No value
CL-USER> #?(some string)
"some string"
CL-USER> #?(some string with a "string" inside)
"some string with a \"string\" inside"
CL-USER> #?(some string with (nested (parentheses)))
"some string with (nested (parentheses))"

Print a raw pathname structure

Using CCL, when I print a pathname using, e.g., (format t "~s" pathname), or with pprint, or with print, it prints out with the #P reader syntax. For instance:
? (make-pathname :directory "foo")
#P"foo/"
? (format t "~s" (make-pathname :directory "foo"))
#P"foo/"
NIL
I'd really like to see the underlying pathname structure, so that I can tell exactly what the object looks like. Is there a way to print it raw?
I don't know if that's what you're looking for, but you could call the inspector
(inspect thing)
CCL example:
? (inspect (make-pathname :directory "foo"))
[0] #P"foo/"
[1] Type: PATHNAME
[2] Class: #<BUILT-IN-CLASS PATHNAME>
[3] TYPE: (PATHNAME . #<CCL::CLASS-WRAPPER PATHNAME #x14083886>)
[4] %PATHNAME-DIRECTORY: (:RELATIVE "foo")
[5] %PATHNAME-NAME: NIL
[6] %PATHNAME-TYPE: NIL
[7] %PHYSICAL-PATHNAME-VERSION: NIL
[8] %PHYSICAL-PATHNAME-DEVICE: NIL
Inspect> help
The following toplevel commands are available:
<n> the same as (:I <n>)
(:S N V) set the <n>th line of object data to value <v>
:HOME show first page of object data
:PREV show previous page of object data
:NEXT show next page of object data
:SHOW re-show currently inspected object (the value of CCL:#)
:Q exit inspector
:POP exit current inspector level
(:I N) inspect <n>th item
:? help
:PWD Print the pathame of the current directory
(:CD DIR) Change to directory DIR (e.g., #p"ccl:" or "/some/dir")
(:PROC &OPTIONAL P) Show information about specified process <p>/all processes
(:KILL P) Kill process whose name or ID matches <p>
(:Y &OPTIONAL P) Yield control of terminal-input to process
whose name or ID matches <p>, or to any process if <p> is null
Any other form is evaluated and its results are printed out.
Inspect>
Example on ideone with CLISP
In addition to inspect, you can use describe:
? (describe #P"/tmp/**/file.*")
#P"/tmp/**/file.*"
Type: PATHNAME
Class: #<BUILT-IN-CLASS PATHNAME>
TYPE: (PATHNAME . #<CCL::CLASS-WRAPPER PATHNAME #x30004003ED0D>)
%PATHNAME-DIRECTORY: (:ABSOLUTE "tmp" :WILD-INFERIORS)
%PATHNAME-NAME: "file"
%PATHNAME-TYPE: :WILD
%PHYSICAL-PATHNAME-VERSION: :NEWEST
%PHYSICAL-PATHNAME-DEVICE: NIL
This is a problem with format directives, change "S" with "A" that prints the string, "S" (try to) prints a valid object that can read the REPL or the function read
; SLIME 2016-04-19
CL-USER> (format t "~s" (make-pathname :directory "foo"))
#P"/foo/"
NIL
CL-USER> (format t "~A" (make-pathname :directory "foo"))
/foo/
NIL
from the tutorial a few format receipes
"~S" tries to generate output that can be read back in with READ.
Thus, strings will be enclosed in quotation marks, symbols will be
package-qualified when necessary, and so on. Objects that don't have a
READable representation are printed with the unreadable object syntax
"<>." With a colon modifier, both the ~A and ~S directives emit NIL as
() rather than NIL. Both the ~A and ~S directives also take up to
four prefix parameters, which can be used to control whether padding is > added after (or before with the at-sign modifier) the value, but those
parameters are only really useful for generating tabular data.
finally only to get the string put nil instead of t wich redirect to standard output
CL-USER> (format nil "~A" (make-pathname :directory "foo"))
"/foo/"

How to pass s-exp to parameter of non s-exp type in Common Lisp?

Question: How to force a s-exp to be evaluated before passing to a function expecting parameter of string type or else.?
This code is fine (no error):
(setf (slot-value (ole sheet :range "A1:B1") 'value)
`(("123" "456"))))
However, when passing a s-exp such as (first line) instead of "123":
(setf line '("123" "456"))
(setf (slot-value (ole sheet :range "A1:B1") 'value)
`(((first line) (second line)))))
There is error message:
The value FIRST is not of the expected type (OR
STRING
FIXNUM
SINGLE-FLOAT
DOUBLE-FLOAT).
[Condition of type TYPE-ERROR]
Restarts:
0: [RETRY] Retry SLIME REPL evaluation request.
1: [*ABORT] Return to SLIME's top level.
2: [ABORT-BREAK] Reset this thread
3: [ABORT] Kill this thread
I know what the problem is. But is there way get rid of this restriction? Because we would need to put the line of code inside a loop, so can't fix the parameter value to such as "123"...
I try using macro:
(defmacro set-line (par1 par2)
`(setf (slot-value (ole sheet :range "A1:B1") 'value)
`((,par1 ,par2))))
However, it doesn't work. Still the same error message saying the wrong type (first line)...
(set-line (first line) (second line))
Also I don't know how to escape the backquote ` if it appears inside macro body. I have tried put a \ in front of backquote inside the macro body, but then the \ would also appear upon macro expand.
`(setf xxx ` <--- another backquote
`(setf xxx \` <--- this can't escape backquote inside macro body
Thanks.
Background: when playing with Win32 OLE Excel example in:
https://github.com/quek/cl-win32ole/blob/master/example/excel.lisp
You are missing the basics of quotation. Your expression
? `(("123" "456")) ; quasiquote
(("123" "456"))
is a list containing a list and can also be created using the function LIST as
? (list (list "123" "456")) ; list
(("123" "456"))
To use expressions, you can either use unquote (note the preceding comma)
? `((,(first line) ,(second line))) ; quasiquote with unquote
(("123" "456"))
or, better
? `(,line)
(("123" "456"))
or use list :
? (list line)
(("123" "456"))

Resources