Skip to content
This repository has been archived by the owner on Oct 7, 2024. It is now read-only.

Commit

Permalink
Merge pull request #26 from xapix-io/missing-text-functions
Browse files Browse the repository at this point in the history
Add ARABIC, VALUE and TEXTJOIN
  • Loading branch information
DeLaGuardo authored Sep 3, 2018
2 parents 8256c5e + 5a5d452 commit 1b919a8
Show file tree
Hide file tree
Showing 8 changed files with 279 additions and 34 deletions.
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ Any expression can be used as an operand for any operator. axel-f has the same o
- [x] [AND](https://support.office.com/en-us/article/and-function-5f19b2e8-e1df-4408-897a-ce285a19e9d9)
- [x] [OR](https://support.office.com/en-us/article/or-function-7d17ad14-8700-4281-b308-00b131e22af0)
- [x] [NOT](https://support.office.com/en-us/article/not-function-9cfc6011-a054-40c7-a140-cd4ba2d87d77)
- [x] [ARABIC](https://support.office.com/en-us/article/arabic-function-9a8da418-c17b-4ef9-a657-9370a30a674f)
- [x] [CLEAN](https://support.office.com/en-us/article/clean-function-26f3d7c5-475f-4a9c-90e5-4b8ba987ba41)
- [x] [CHAR](https://support.office.com/en-us/article/char-function-bbd249c8-b36e-4a91-8017-1c133f9b837a)
- [x] [CODE](https://support.office.com/en-us/article/code-function-c32b692b-2ed0-4a04-bdd9-75640144b928)
Expand All @@ -120,15 +121,21 @@ Any expression can be used as an operand for any operator. axel-f has the same o
- [x] [LOWER](https://support.office.com/en-us/article/lower-function-3f21df02-a80c-44b2-afaf-81358f9fdeb4)
- [x] [MID](https://support.office.com/en-us/article/mid-midb-functions-d5f9e25c-d7d6-472e-b568-4ecb12433028)
- [x] [PROPER](https://support.office.com/en-us/article/proper-function-52a5a283-e8b2-49be-8506-b2887b889f94)
- [x] [REGEXEXTRACT](https://support.google.com/docs/answer/3098244?hl=en&ref_topic=3105625)
- [x] [REGEXMATCH](https://support.google.com/docs/answer/3098292?hl=en&ref_topic=3105625)
- [x] [REGEXREPLACE](https://support.google.com/docs/answer/3098245?hl=en&ref_topic=3105625)
- [x] [REPLACE](https://support.office.com/en-us/article/replace-replaceb-functions-8d799074-2425-4a8a-84bc-82472868878a)
- [x] [REPT](https://support.office.com/en-us/article/rept-function-04c4d778-e712-43b4-9c15-d656582bb061)
- [x] [RIGHT](https://support.office.com/en-us/article/right-rightb-functions-240267ee-9afa-4639-a02b-f19e1786cf2f)
- [x] [ROMAN](https://support.office.com/en-us/article/roman-function-d6b0b99e-de46-4704-a518-b45a0f8b56f5)
- [x] [SEARCH](https://support.office.com/en-us/article/search-searchb-functions-9ab04538-0e55-4719-a72e-b6f54513b495)
- [x] [SPLIT](https://support.google.com/docs/answer/3094136)
- [x] [SUBSTITUTE](https://support.office.com/en-us/article/substitute-function-6434944e-a904-4336-a9b0-1e58df3bc332)
- [x] [T](https://support.office.com/en-us/article/t-function-fb83aeec-45e7-4924-af95-53e073541228)
- [x] [TRIM](https://support.office.com/en-us/article/trim-function-410388fa-c5df-49c6-b16c-9e5630b479f9)
- [x] [UPPER](https://support.office.com/en-us/article/upper-function-c11f29b3-d1a3-4537-8df6-04d0049963d6)
- [x] [VALUE](https://support.office.com/en-us/article/value-function-257d0108-07dc-437d-ae1c-bc2d3953d8c2)
- [x] [TEXTJOIN](https://support.office.com/en-us/article/textjoin-function-357b449a-ec91-49d0-80c3-0e8fc845691c)
- [x] [COUNT](https://support.office.com/en-us/article/count-function-a59cd7fc-b623-4d93-87a4-d23bf411294c)
- [x] [IF](https://support.office.com/en-us/article/if-function-69aed7c9-4e8a-4755-a9bc-aa8bbff73be2)

Expand All @@ -145,7 +152,6 @@ In addition we have special functions for accessing the data in context: `OBJREF
- [ ] [ADDRESS](https://support.office.com/en-us/article/address-function-d0c26c0d-3991-446b-8de4-ab46431d4f89)
- [ ] [AMORDEGRC](https://support.office.com/en-us/article/amordegrc-function-a14d0ca1-64a4-42eb-9b3d-b0dededf9e51)
- [ ] [AMORLINC](https://support.office.com/en-us/article/amorlinc-function-7d417b45-f7f5-4dba-a0a5-3451a81079a8)
- [ ] [ARABIC](https://support.office.com/en-us/article/arabic-function-9a8da418-c17b-4ef9-a657-9370a30a674f)
- [ ] [AREAS](https://support.office.com/en-us/article/areas-function-8392ba32-7a41-43b3-96b0-3695d2ec6152)
- [ ] [ASC](https://support.office.com/en-us/article/asc-function-0b6abf1c-c663-4004-a964-ebc00b723266)
- [ ] [ASIN](https://support.office.com/en-us/article/asin-function-81fb95e5-6d6f-48c4-bc45-58f955c6d347)
Expand Down Expand Up @@ -517,7 +523,6 @@ In addition we have special functions for accessing the data in context: `OBJREF
- [ ] [SUMXMY2](https://support.office.com/en-us/article/sumxmy2-function-9d144ac1-4d79-43de-b524-e2ecee23b299)
- [ ] [SWITCH](https://support.office.com/en-us/article/switch-function-47ab33c0-28ce-4530-8a45-d532ec4aa25e)
- [ ] [SYD](https://support.office.com/en-us/article/syd-function-069f8106-b60b-4ca2-98e0-2a0f206bdb27)
- [ ] [T](https://support.office.com/en-us/article/t-function-fb83aeec-45e7-4924-af95-53e073541228)
- [ ] [TAN](https://support.office.com/en-us/article/tan-function-08851a40-179f-4052-b789-d7f699447401)
- [ ] [TANH](https://support.office.com/en-us/article/tanh-function-017222f0-a0c3-4f69-9787-b3202295dc6c)
- [ ] [TBILLEQ](https://support.office.com/en-us/article/tbilleq-function-2ab72d90-9b4d-4efe-9fc2-0f81f2c19c8c)
Expand All @@ -528,7 +533,6 @@ In addition we have special functions for accessing the data in context: `OBJREF
- [ ] [T.DIST.RT](https://support.office.com/en-us/article/tdistrt-function-20a30020-86f9-4b35-af1f-7ef6ae683eda)
- [ ] [TDIST](https://support.office.com/en-us/article/tdist-function-630a7695-4021-4853-9468-4a1f9dcdd192)
- [ ] [TEXT](https://support.office.com/en-us/article/text-function-20d5ac4d-7b94-49fd-bb38-93d29371225c)
- [ ] [TEXTJOIN](https://support.office.com/en-us/article/textjoin-function-357b449a-ec91-49d0-80c3-0e8fc845691c)
- [ ] [TIME](https://support.office.com/en-us/article/time-function-9a5aff99-8f7d-4611-845e-747d0b8d5457)
- [ ] [TIMEVALUE](https://support.office.com/en-us/article/timevalue-function-0b615c12-33d8-4431-bf3d-f3eb6d186645)
- [ ] [T.INV](https://support.office.com/en-us/article/tinv-function-2908272b-4e61-4942-9df9-a25fec9b0e2e)
Expand All @@ -545,7 +549,6 @@ In addition we have special functions for accessing the data in context: `OBJREF
- [ ] [TYPE](https://support.office.com/en-us/article/type-function-45b4e688-4bc3-48b3-a105-ffa892995899)
- [ ] [UNICHAR](https://support.office.com/en-us/article/unichar-function-ffeb64f5-f131-44c6-b332-5cd72f0659b8)
- [ ] [UNICODE](https://support.office.com/en-us/article/unicode-function-adb74aaa-a2a5-4dde-aff6-966e4e81f16f)
- [ ] [VALUE](https://support.office.com/en-us/article/value-function-257d0108-07dc-437d-ae1c-bc2d3953d8c2)
- [ ] [VAR](https://support.office.com/en-us/article/var-function-1f2b7ab2-954d-4e17-ba2c-9e58b15a7da2)
- [ ] [VAR.P](https://support.office.com/en-us/article/varp-function-73d1285c-108c-4843-ba5d-a51f90656f3a)
- [ ] [VAR.S](https://support.office.com/en-us/article/vars-function-913633de-136b-449d-813e-65a00b2b990b)
Expand Down
2 changes: 1 addition & 1 deletion deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
:test {:extra-paths ["test"]
:extra-deps {org.clojure/test.check {:mvn/version "RELEASE"}}}

:coverage {:extra-deps {cloverage {:mvn/version "1.0.11"}}
:coverage {:extra-deps {cloverage {:mvn/version "RELEASE"}}
:main-opts ["-m" "cloverage.coverage"
"--src-ns-path" "src"
"--test-ns-path" "test"
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>io.xapix</groupId>
<artifactId>axel-f</artifactId>
<version>0.2.1</version>
<version>0.2.2-SNAPSHOT</version>
<name>axel-f</name>
<dependencies>
<dependency>
Expand Down
2 changes: 1 addition & 1 deletion release-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "axel-f",
"version": "0.2.1",
"version": "0.2.2-SNAPSHOT",
"description": "axel-f is an engine that can evaluate excel-like expressions.",
"homepage": "https://github.com/xapix-io/axel-f",
"author": "Kirill Chernyshov (https://github.com/DeLaGuardo)",
Expand Down
6 changes: 6 additions & 0 deletions src/axel_f/error.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@
arg-position
(when arg-position " ")
"expects number values. But '" value "' is a text and cannot be coerced to a number."))

(defn format-not-a-string-error [fnname arg-position value]
(str "Function " fnname " parameter "
arg-position
(when arg-position " ")
"expects text values. But '" value "' is a number and cannot be coerced to a string."))
42 changes: 40 additions & 2 deletions src/axel_f/functions.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@
:desc "Returns the text with the non-printable ASCII characters removed."
:args [{:desc "The text whose non-printable characters are to be removed."}]}

"ARABIC" {:impl #'text/arabic-fn
:desc "Computes the value of a Roman numeral."
:args [{:desc "The Roman numeral to format, whose value must be between 1 and 3999, inclusive."}]}

"CHAR" {:impl #'text/char-fn
:desc "Convert a number into a character according to the current Unicode table."
:args [{:desc "The number of the character to look up from the current Unicode table in decimal format."}]}
Expand All @@ -74,7 +78,7 @@
:desc "Returns the numeric Unicode map value of the first character in the string provided."
:args [{:desc "The string whose first character's Unicode map value will be returned."}]}

"CONCATENATE" {:impl (partial text/join-fn "")
"CONCATENATE" {:impl (partial text/textjoin-fn "" false)
:desc "Appends strings to one another."
:args [{:desc "The initial string."}
{:desc "More strings to append in sequence."
Expand All @@ -99,7 +103,8 @@
{:desc "The character within arg2 at which to start the search."
:opt true}]}

"JOIN" {:impl #'text/join-fn
"JOIN" {:impl (fn [delimeter & args]
(apply text/textjoin-fn delimeter false args))
:desc "Concatenates the elements of one or more one-dimensional arrays using a specified delimiter."
:args [{:desc "The character or string to place between each concatenated value."}
{:desc "The value or values to be appended using arg1."}
Expand Down Expand Up @@ -131,6 +136,22 @@
:desc "Capitalizes each word in a specified string."
:args [{:desc "The text which will be returned with the first letter of each word in uppercase and all other letters in lowercase."}]}

"REGEXEXTRACT" {:impl #'text/regexextract-fn
:desc "Extracts matching substrings according to a regular expression."
:args [{:desc "The input text."}
{:desc "The first part of arg1 that matches this expression will be returned."}]}

"REGEXMATCH" {:impl #'text/regexmatch-fn
:desc "Whether a piece of text matches a regular expression."
:args [{:desc "The text to be tested against the regular expression."}
{:desc "The regular expression to test the text against."}]}

"REGEXREPLACE" {:impl #'text/regexreplace-fn
:desc "Replaces part of a text string with a different text string using regular expressions."
:args [{:desc "The text, a part of which will be replaced."}
{:desc "The regular expression. All matching instances in text will be replaced."}
{:desc "The text which will be inserted into the original text."}]}

"REPLACE" {:impl #'text/replace-fn
:desc "Replaces part of a text string with a different text string."
:args [{:desc "The text, a part of which will be replaced."}
Expand Down Expand Up @@ -177,6 +198,10 @@
{:desc "The instance of arg2 within arg1 to replace with arg3. By default, all occurrences of arg2 are replaced; however, if arg4 is specified, only the indicated instance of arg2 is replaced."
:opt true}]}

"T" {:impl #'text/t-fn
:desc "Returns string arguments as text."
:args [{:desc "The argument to be converted to text."}]}

"TRIM" {:impl #'text/trim-fn
:desc "Removes leading, trailing, and repeated spaces in text."
:args [{:desc "The text or reference to a cell containing text to be trimmed."}]}
Expand All @@ -185,6 +210,19 @@
:desc "Converts a specified string to uppercase."
:args [{:desc "The string to convert to uppercase."}]}

"VALUE" {:impl #'text/value-fn
:desc "Converts a string in any of the date, time or number formats that axel-f understands into a number."
:args [{:desc "The string containing the value to be converted."}]}

"TEXTJOIN" {:impl #'text/textjoin-fn
:desc "Combines the text from multiple strings and/or arrays, with a specifiable delimiter separating the different texts."
:args [{:desc "A string, possibly empty, or a reference to a valid string. If empty, text will be simply concatenated."}
{:desc "A boolean; if TRUE, empty strings selected in the text arguments won't be included in the result."}
{:desc "Any text item. This could be a string, or an array of strings in a range."}
{:desc "Additional text item(s)."
:opt true
:repeatable true}]}

"COUNT" {:impl #'stat/count-fn
:desc "Returns a count of the number of numeric values in a dataset."
:args [{:desc "The first value or range to consider when counting."}
Expand Down
113 changes: 88 additions & 25 deletions src/axel_f/functions/text.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,29 @@
(or (get cmap pattern) pattern)
(string/escape pattern cmap))))

;; TODO
;; (defn arabic-fn [roman-numeral])
(def roman-numerals
{\I 1 \V 5 \X 10 \L 50
\C 100 \D 500 \M 1000 "IV" 4
"IX" 9 "XL" 40 "XC" 90 "CD" 400
"CM" 900})

(defn arabic-fn [s]
(let [sign (if (string/starts-with? s "-")
-1 1)
s (partition-all 2 (vec (string/replace-first s #"-" "")))]
(loop [acc 0 current (first s) other (rest s)]
(if current
(let [is-pair? (get roman-numerals (apply str current))
value (or is-pair?
(get roman-numerals (first current)))]
(if is-pair?
(recur (+ acc value) (first other) (rest other))
(let [new-other (->> (concat current other)
flatten
rest
(partition-all 2))]
(recur (+ acc value) (first new-other) (rest new-other)))))
(* sign acc)))))

;; TODO
;; (defn asc-fn [])
Expand Down Expand Up @@ -69,12 +90,6 @@
;; TODO
;; (defn fixed-fn [])

(defn join-fn [delimeter & items]
(->> items
flatten
(map coercion/excel-str)
(string/join delimeter)))

(defn left-fn
([text] (left-fn text 1))
([text number]
Expand Down Expand Up @@ -113,14 +128,53 @@
(defn proper-fn [text]
(string/replace (coercion/excel-str text) #"\w*" string/capitalize))

;; TODO
;; (defn regexextract-fn [])
(defn regexextract-fn [text regular-expression]
(cond
(not (string? text))
(throw (error/error "#VALUE!"
(error/format-not-a-string-error "REGEXEXTRACT" 1 text)))

;; TODO
;; (defn regexmatch-fn [])
(not (string? regular-expression))
(throw (error/error "#VALUE!"
(error/format-not-a-string-error "REGEXEXTRACT" 2 regular-expression)))

:otherwise
(let [res (re-find (re-pattern regular-expression)
text)]
(cond
(string? res) res
(vector? res) (second res)
:otherwise res))))

(defn regexmatch-fn [text regular-expression]
(cond
(not (string? text))
(throw (error/error "#VALUE!"
(error/format-not-a-string-error "REGEXMATCH" 1 text)))

;; TODO
;; (defn regexreplace-fn [])
(not (string? regular-expression))
(throw (error/error "#VALUE!"
(error/format-not-a-string-error "REGEXMATCH" 2 regular-expression)))

:otherwise
(boolean (regexextract-fn text regular-expression))))

(defn regexreplace-fn [text regular-expression replacement]
(cond
(not (string? text))
(throw (error/error "#VALUE!"
(error/format-not-a-string-error "REGEXREPLACE" 1 text)))

(not (string? regular-expression))
(throw (error/error "#VALUE!"
(error/format-not-a-string-error "REGEXREPLACE" 2 regular-expression)))

(not (string? replacement))
(throw (error/error "#VALUE!"
(error/format-not-a-string-error "REGEXREPLACE" 3 replacement)))

:otherwise
(string/replace text (re-pattern regular-expression) replacement)))

(defn replace-fn
[text position length new-text]
Expand Down Expand Up @@ -155,11 +209,7 @@
(if-let [n (coercion/excel-number n)]
(if (<= 0 n 3999)
(let [n (int n)
alphabet (sort-by val >
{\I 1 \V 5 \X 10 \L 50
\C 100 \D 500 \M 1000 "IV" 4
"IX" 9 "XL" 40 "XC" 90 "CD" 400
"CM" 900})]
alphabet (sort-by val > roman-numerals)]
(loop [res "" n n]
(if (zero? n) res
(let [[rom arab] (some #(when (<= (val %) n) %) alphabet)]
Expand Down Expand Up @@ -215,8 +265,9 @@
(throw (error/error "#VALUE!"
(error/format-not-a-number-error "SUBSTITUTE" 4 occurrence)))))

;; TODO
;; (defn t-fn [])
(defn t-fn [value]
(when (string? value)
value))

;; TODO
;; (defn text-fn [])
Expand All @@ -231,8 +282,20 @@
coercion/excel-str
string/upper-case))

;; TODO
;; (defn value-fn [])
(defn value-fn [s]
(or
(when (and (seqable? s)
(empty? s))
0)
(when-not (boolean? s)
(coercion/excel-number s))
(throw (error/error "#VALUE!" (str "VALUE parameter '" (coercion/excel-str s) "' cannot be parsed to number.")))))

;; TODO
;; (defn textjoin-fn [])
(defn textjoin-fn [delimeter ignore-empty & items]
(->> items
flatten
(map coercion/excel-str)
(filter (if ignore-empty
not-empty
identity))
(string/join delimeter)))
Loading

0 comments on commit 1b919a8

Please sign in to comment.