(DrRacket) String manipulation problem creating student emails - racket

I am having trouble with finding the part of the string for the 1st name when the goose email length is less then 9
(check-expect( goose-mail "becky""anderson"12)"12abecky#uragoose.ca")
At Goose University, students are given a unique username based on their name and a special ID
number. The username starts with the special ID number, followed by the first letter of their last
name, and then followed by their first name. All of the usernames are restricted to a maximum of
9 letters, therefore it is often the case that only a portion of the first name is included. All of the
usernames are in lower case. The special ID number is a positive integer that is less than 1000. The
email address is the username with “#uragoose.ca" appended to it.
Write a Racket function goose-mail that consumes two non-empty strings first-name, last-name,
and a non-negative integer ID-num, where 0 ≤ ID-num ≤ 999 and produces the email address for the
student with the specified first and last names and ID number. The first name and last name are
provided in lower case.
>
What I have so far is
(check-expect(1st-last-name-letter "pham")"p")
(define(1st-last-name-letter L)
(substring L 0 1))
(check-expect(ID-num 12)"12")
(define (ID-num ID)
(number->string ID))
(check-expect(user-name "andrew" "pham" 123)"123pandrew")
(define(user-name first-name last-name ID)
(string-append (string-append(ID-num ID)(1st-last-name-letter last-name))
first-name) )

We just need to check the length of the resulting username, and trim it to the required size if necessary:
(define (user-name first-name last-name ID)
(let ((username (string-append (ID-num ID) (1st-last-name-letter last-name) first-name)))
(if (<= (string-length username) 9)
username
(substring username 0 9))))

Related

Checking user input in Racket

I am getting an input from a user for a tex-field% in racket which would look something like this:
open button a = fwd; button b = xxx; button s = xxx; close
I have verified that it does contain open and close at beginning and end respectively. But now i need to store each of the substrings based on the semicolons to check them for semicolons at the end, among other things. For example, in the example above it should store 3 substrings in a vector/list (whichever is easier). It would be stored as:
button a = fwd;
button b = xxx;
button s = xxx;
;input is the name of the string the user enters
(define vec (apply vector (string-split input)))
(define vecaslist(vector->list vec))
(define removedopen (cdr vecaslist))
(define withoutopenandclose (reverse(cdr(reverse removedopen))))
(define stringwithoutopen (string-replace input "open " ""))
(define stringtoderivate (string-replace stringwithoutopen " close" ""))
(define tempvec (apply vector (string-split stringtoderivate ";" #:trim? #f #:repeat? #t)))
Attempted to split it by semicolons and place in a vector, but it removes the semicolons. When i do print the length of the vector it correctly shows 3 though, but i would like to keep the semicolons for now.
You can use string-split with a regular expression separator, as follows:
(string-split input #rx"(open | close)|(?<=;).")
which will output the list:
'("button a = fwd;" "button b = xxx;" "button s = xxx;")
To break down the regular expression:
(exp) matches any sub-expression "exp". Hence, (open ) matches the sub-expression "open " in input. Similarly with ( close), matching " close".
(?<=exp) does a positive look-behind, matching if "exp" matches preceding.
. matches anything, such as whitespace, characters etc.
| matches either the expression that comes before it, or after it, trying left first.

Emacs repeat until a given column?

When adding a divider in code I can easily repeat a '=' N times using
C-<N> =
where N is the number of equal signs to insert.
Is there a similarly quick command that would insert a character repeatedly up to a given column number? So I could execute
<magic command>-<N> =
and get a line of equal signs from the present cursor position to column N?
I don't know of anything built in that can do that, but you could bind the function below to a key sequence of your choice:
(defun repeat-char-to-column (column character)
"Insert copies of CHARACTER on the current line until column COLUMN.
Interactively, prompt for COLUMN and CHARACTER. If the current column is
equal to or greater than COLUMN, do nothing."
(interactive "nRepeat to column: \ncCharacter to repeat: \n")
(let ((cur (current-column)))
(if (< cur column)
(insert (make-string (- column cur) character)))))

How to retrieve a name of the frame in Emacs?

I'd like to retrieve a name of the current frame using elisp. I have discovered that name is a part of frame's properties. The properties is an associated list. I do the following:
(cdr (assoc 'name (frame-parameters)))
But instead of the expected name I receive a mixed list of the name and some properties:
#("main-1" 0 5 (face nil) 5 6 (face nil))
How can I extract "main-1" from this?
There are text properties on that string. You can use substring-no-properties to extract the plain string.
(substring-no-properties
(cdr (assoc 'name (frame-parameters))))
Note that you may not need to do this. The propertized string is still a string, and equal to its no-properties version.
See also: C-hig (elisp) Text Props and Strings RET

Emacs byte-to-position function is not consistent with document?

Emacs 24.3.1, Windows 2003
I found the 'byte-to-position' function is a little strange.
According to the document:
-- Function: byte-to-position byte-position
Return the buffer position, in character units, corresponding to
given BYTE-POSITION in the current buffer. If BYTE-POSITION is
out of range, the value is `nil'. **In a multibyte buffer, an
arbitrary value of BYTE-POSITION can be not at character boundary,
but inside a multibyte sequence representing a single character;
in this case, this function returns the buffer position of the
character whose multibyte sequence includes BYTE-POSITION.** In
other words, the value does not change for all byte positions that
belong to the same character.
We can make a simple experiment:
Create a buffer, eval this expression: (insert "a" (- (max-char) 128) "b")
Since the max bytes number in Emacs' internal coding system is 5, the character between 'a' and 'b' is 5 bytes. (Note that the last 128 characters is used for 8 bits raw bytes, their size is only 2 bytes.)
Then define and eval this test function:
(defun test ()
(interactive)
(let ((max-bytes (1- (position-bytes (point-max)))))
(message "%s"
(loop for i from 1 to max-bytes collect (byte-to-position i)))))
What I get is "(1 2 3 2 2 2 3)".
The number in the list represents the character position in the buffer. Because there is a 5 bytes big character, there should be five '2' between '1' and '3', but how to explain the magic '3' in the '2's ?
This was a bug. I no longer see this behavior in 26.x. You can read more about it here (which actually references this SO question).
https://debbugs.gnu.org/cgi/bugreport.cgi?bug=20783

What's the corresponding standard function of atoi in clisp?

In visual lisp, you can use (atoi "123") to convert "123" to 123. It seems there is no "atoi" like function in clisp ?
any suggestion is appreciated !
Now i want to convert '(1 2 3 20 30) to "1 2 3 20 30", then what's the best way to do it ?
parse-interger can convert string to integer, and how to convert integer to string ? Do i need to use format function ?
(map 'list #'(lambda (x) (format nil "~D" x)) '(1 2 3)) => ("1" "2" "3")
But i donot know how to cnovert it to "1 2 3" as haskell does:
concat $ intersperse " " ["1","2","3","4","5"] => "1 2 3 4 5"
Sincerely!
In Common Lisp, you can use the read-from-string function for this purpose:
> (read-from-string "123")
123 ;
3
As you can see, the primary return value is the object read, which in this case happens to be an integer. The second value—the position—is harder to explain, but here it indicates the next would-be character in the string that would need to be read next on a subsequent call to a reading function consuming the same input.
Note that read-from-string is obviously not tailored just for reading integers. For that, you can turn to the parse-integer function. Its interface is similar to read-from-string:
> (parse-integer "123")
123 ;
3
Given that you were asking for an analogue to atoi, the parse-integer function is the more appropriate choice.
Addressing the second part of your question, post-editing, you can interleave (or "intersperse") a string with the format function. This example hard-codes a single space character as the separating string, using the format iteration control directives ~{ (start), ~} (end), and ~^ (terminate if remaining input is empty):
> (format nil "Interleaved: ~{~S~^ ~}." '(1 2 3))
"Interleaved: 1 2 3."
Loosely translated, the format string says,
For each item in the input list (~{), print the item by its normal conversion (~S). If no items remain, stop the iteration (~^). Otherwise, print a space, and then repeat the process with the next item (~}).
If you want to avoid hard-coding the single space there, and accept the separator string as a separately-supplied value, there are a few ways to do that. It's not clear whether you require that much flexibility here.