Creating a string of blank characters - clojure

How would one construct a code that inserts b blank characters in between two input strings?
Concretely I am asking about a function which inputs
(newfn "AAA" "ZZZ" 10)
and outputs 10 blanks between the strings "AAA" and "ZZZ"

(defn wrap-spaces [h t n]
(let [blanks (apply str (repeat n " "))]
(str h blanks t)))
(wrap-spaces "AAA" "ZZZ" 10)

Related

Comparing two strings and returning the number of matched words

I'm fairly new to Clojure, and in programming, in general.
Is there a way I can compare two strings word by word and then return the number of matched words in both strings? Also how can I count the numbers in a string?
Ex:
comparing string1 "Hello Alan and Max" and string2 "Hello Alan and Bob" will return "3" (such as Hello Alan and are the words matched in both strings)
and finding the number of words in string1 will result in the number 4.
Thank you
Let's break it down into some smaller problems:
compare two strings word by word
First we'll need a way to take a string and return its words. One way to do this is to assume any whitespace is separating words, so we can use a regular expression with clojure.string/split:
(defn string->words [s]
(clojure.string/split s #"\s+"))
(string->words "Hello world, it's me, Clojure.")
=> ["Hello" "world," "it's" "me," "Clojure."]
return the number of matched words in both strings
The easiest way I can imagine doing this is to build two sets, one to represent the set of words in both sentences, and finding the intersection of the two sets:
(set (string->words "a b c a b c d e f"))
=> #{"d" "f" "e" "a" "b" "c"} ;; #{} represents a set
And we can use the clojure.set/intersection function to find the intersection of two sets:
(defn common-words [a b]
(let [a (set (string->words a))
b (set (string->words b))]
(clojure.set/intersection a b)))
(common-words "say you" "say me")
=> #{"say"}
To get the count of (matching) words, we can use the count function with the output of the above functions:
(count (common-words "say you" "say me")) ;; => 1
what you need to do, is to compare word sequences' items pairwise, and count the number of items until the first mismatch. Here is an almost word for word translation of this:
(defn mismatch-idx [s1 s2]
(let [w #"\S+"]
(->> (map = (re-seq w s1) (re-seq w s2))
(take-while true?)
count)))
user> (mismatch-idx "a b c" "qq b c")
;;=> 0
user> (mismatch-idx "a b c" "a x c")
;;=> 1
user> (mismatch-idx "a b c" "a b x")
;;=> 2

Read a file containing data and print values 10 characters before and after into a new file if string "john" is found

I need to print 10 characters before and after string "john",whenever "john" is encountered. Even though half of letters are printed in the next line,it should still print 10 characters before and after.
I have tried using .contains function and using the index of string but the problem arises when i input a file like this:
Hello my name is jo
hn and i work for bla bla.
What I tried:
(ns clojure-assignment.problem6
(:use [clojure.string :only [index-of]]))
(defn String_manipulation []
(def str1 (slurp "string.txt"))
(println str1)
(def check (.contains str1 "john"))
(if (= check true)
(def index (index-of str1 "john")))
(println (subs str1 (- index 11) index))
(println (subs str1 (+ index 4) (+ index 5 10))))
(String_manipulation)
I expect the output to print values 10 characters before and after the given string and it should also work if there is a line end.
You can use this:
(def s "Hello my name is jo
hn and i work for bla bla.
")
(re-seq #".{10}john.{10}" (str/replace s #"\n" ""))
;; => ("y name is john and i wor")
UPDATE 1 - overlapping pattern
If pattern is expected to be overlapping, use look ahead regex and extract from the matched group:
(def s "hello my name is john-john and john is my father's name")
(re-seq #"(?=(.{10}john.{10}))" (str/replace s #"\n" ""))
(["" "y name is john-john and "]
["" "e is john-john and john "]
["" "-john and john is my fat"])
UPDATE 2 - print prefix and suffix match group
(use 'clojure.pprint)
(def s "Hello my name is jo
hn and i work for bla bla.
")
(->> (str/replace s #"\n" "")
(re-seq #"(?=(.{10})john(.{10}))")
(cl-format *out* "~{~{~a~}~%~}"))
;; => y name is and i wor

Clojure: Manipulating certain items in list

I'm a Clojure newbie and having trouble with its immutable state. I'm trying to write a function that takes a list with the frames of a bowling game. For example, a list would look like ["X" "12" "2/" "X" "45" "X" "13" "33" "X" "81"]. I want the function to output a list that takes care of the frames that just have integers, and adds the numbers together. So, if the list above was inputted, the following list would be outputted: ["X" "3" "2/" "X" "9" "X" "4" "6" "X" "9"]. This was my attempt, but immutable state in Clojure is making it hard for me to understand how to go about this:
(defn eval-frames
[flist]
(loop [frames '()]
(if (not (= flist '()))
frames
(eval-normal (rest flist)))
(if (not (or (spare? flist) (strike? flist) (= flist ())))
(conj frames (+ (get (first flist) 0) ((get (first flist) 1))))
(conj frames (first flist)))
)
)
This just ends up outputting the first frame in the list, instead of the entire list. Any suggestions would be extremely appreciated!
There's a fair amount wrong with the code you posted:
The whole (if (not (= flist '())) part does nothing since you never use the results it gives back. You're thinking too imperative here. conj returns the "modified" list, it doesn't alter the original!
You never recur in the loop, so the loop only ever runs once.
I'd just use map for this. It iterates over a list, and "transforms" each element based on a function. I highly recommend getting as used to map and reduce as you can, because you'll be using them constantly.
My plan was this:
If all the characters in the frame are digits, sum the frame, else, leave the frame alone.
To sum the frame, I'm using parseLong to turn each character into a number, then(apply + to sum the parsed numbers, and then str to turn it back into a String.
(map
(fn [frame]
; Almost reads like English!
(if (every? #(Character/isDigit %) frame)
(->> frame ; Take the frame...
(map #(Long/parseLong (str %))) ; parse each character in the frame...
(apply +) ; then sum the parsed numbers...
(str)) ; and turn them back into a string.
frame)) ; Else, do nothing and leave the frame alone
["X" "12" "2/" "X" "45" "X" "13" "33" "X" "81"])
=> ("X" "3" "2/" "X" "9" "X" "4" "6" "X" "9")
This would have been simplified a bit if you had stored the scores as numbers originally instead of converting them to Strings. That would prevent the need for Long/parseLong, and the final call to str to turn each summed frame back into a String.
(map #(if (every? (fn [c] (<= (int \0) (int c) (int \9))) %)
(str (apply + (map read-string (map str %))))
%)
["X" "12" "2/" "X" "45" "X" "13" "33" "X" "81"])
or without the read-string:
(map #(if (every? (fn [c] (<= (int \0) (int c) (int \9))) %)
(str (apply + (map (fn [c] (- (int c) (int \0))) %)))
%)
["X" "12" "2/" "X" "45" "X" "13" "33" "X" "81"])
=> ("X" "3" "2/" "X" "9" "X" "4" "6" "X" "9")
(defn eval-frames [frames]
(map #(if (re-find #"\d\d" %)
(reduce + (map (fn [i](Integer. (str i))) (seq %))) %) frames))
So evaluating with a given frame would give :
(eval-frames ["X" "12" "2/" "X" "45" "X" "13" "33" "X" "81"])
=> ("X" "3" "2/" "X" "9" "X" "4" "6" "X" "9")

Write a function to print (non-negative) integer numbers in full words in Clojure

(defn num-as-words [n]
(let [words '("zero" "one" "two" "three" "four"
"five" "six" "seven" "eight" "nine")]
(clojure.string/join "-"
(map (fn [x] (nth words (Integer. (re-find #"\d" (str x)) ))) (str n)))))
I've written this function called as num-as-words which takes an integer and displays it as full words, for example if you were to input (123) it would return (one-two-three).
I've done it using a map but I was wondering if there was another way of doing it? I was also wondering if there was another way to connect the words rather than clojure.string/join, I was initially using interpose but didn't like the way it was outputting, as it looked like ("one" "-" "two" "-" "three").
Any help would be greatly appreciated, thank you.
user=> (clojure.pprint/cl-format ; formatted printing
nil ; ... to a string
"~{~R~^-~}" ; format (see below)
(map ; map over characters
(fn [x] (Integer. (str x))) ; convert char to integer
(str 123))) ; convert number to string
"one-two-three"
First, we take the input number, here hard-coded as "123" in the example, coerce it as a string and iterate over the resulting string's characters thanks to map. For each character, we build a string containing that character and parse it as an Integer. Thus, we obtain a list of digits.
More precisely, (fn [x] ...) is a function taking one argument. You should probably name it char instead (sorry), because we iterate over characters. When we evaluate (str x), we obtain a string containing one char, namely x. For example, if the character is \2, the resulting string is "2". The (Integer. string) form (notice the dot!) calls the constructor for the Integer class, which parse a string as an integer. To continue with our example, (Integer. "2") would yield the integer 2.
We use cl-format to print the list of digits into a fresh string (as requested by the false argument). In order to do that, we specify the format as follows:
~{...~} iterates over a list and executes the format inside the braces for each element.
~R prints a number as an english word (1 => one, etc.)
~^ escapes the iteration made by ~{...~} when there is no remaining arguments. So when we print the last digit, the part that follows ~^ is not printed.
What follows ~^ is simply the character -. This is used to separate strings but we had to take care to not print a dash for all iterations of the loop, otherwise the resulting string would have ended with a dash.
If any character cannot be parsed as an Integer then the function will report an error. You might want to check first that the input really is a positive integer before converting it to a string.
I'd implement it like this:
(defn num-as-words [n]
(let [words ["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"]]
(->> (str n)
(map #(Character/getNumericValue %))
(map words)
(clojure.string/join "-"))))
Using vector will simplify the implementation.
Instead of splitting number string with regular expression, you can treat it as sequence. In this case, you should use Charactor/getNumericValue to convert char to integer.
You can use ->> macro.
Using clojure.string/join looks fine.
interpose returns lazy sequence. That's why it returns like ("one" "-" "two"...). You should apply str to the result, (apply str (interpose ...)) to convert it to string.
If you want to handle negative numbers, you can modify the code like this:
(defn num-as-words [n]
(if (< n 0)
(str "-" (num-as-words (- n)))
(let [words ["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"]]
(->> (str n)
(map #(Character/getNumericValue %))
(map words)
(clojure.string/join "-")))))
This will prepend - in the front. If you just want to throw an error, you can use precondition:
(defn num-as-words [n]
{:pre [(<= 0 n)]}
(let [words ["zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"]]
...
This will throw AssertionError when it receives negative number.

How to convert a clojure string of numbers into separate integers?

I can read some data in like this in the repl. For a real program I plan to assign in a let special form.
(def x1 (line-seq (BufferedReader. (StringReader. x1))))
If I enter 5 5, x1 is bound to ("5 5")
I would like to convert this list of one element into a list of two integers. How can I do that? I have been playing around with parsing the string on whitespace, but am having trouble performing the conversion to integer.
Does this help? In Clojure 1.3.0:
(use ['clojure.string :only '(split)])
(defn str-to-ints
[string]
(map #(Integer/parseInt %)
(split string #" ")))
(str-to-ints "5 4")
; => (5 4)
(apply str-to-ints '("5 4"))
; => (5 4)
In case the Clojure version you're using doesn't have clojure.string namespace you can skip the use command and define the function in a following way.
(defn str-to-ints
[string]
(map #(Integer/parseInt %)
(.split #" " string)))
You can get rid of regular expressions by using (.split string " ") in the last line.
Works for all numbers and returns nil in the case it isn't a number (so you can filter out nils in the resulting seq)
(require '[clojure.string :as string])
(defn parse-number
"Reads a number from a string. Returns nil if not a number."
[s]
(if (re-find #"^-?\d+\.?\d*$" s)
(read-string s)))
E.g.
(map parse-number (string/split "1 2 3 78 90 -12 0.078" #"\s+"))
; => (1 2 3 78 90 -12 0.078)
The string can be wrapped with brackets and after that evaluated as clojure list with read-string function:
(def f #(read-string (str "(" % ")")))
(f "5 4")
; => (5 4)