spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
[Text.SEARCH] formula added and tested
author
Ben Vogt <[email protected]>
date
2017-10-08 16:38:57
stats
8 file(s) changed, 101 insertions(+), 7 deletions(-)
files
DOCS.md
TODO.md
dist/Formulas/AllFormulas.js
dist/Formulas/Text.js
src/Formulas/AllFormulas.ts
src/Formulas/Text.ts
tests/Formulas/TextTest.ts
tests/SheetFormulaTest.ts
  1diff --git a/DOCS.md b/DOCS.md
  2index 6976c42..478d921 100644
  3--- a/DOCS.md
  4+++ b/DOCS.md
  5@@ -2451,3 +2451,13 @@
  6 @returns {string} 
  7 @constructor
  8 ```
  9+
 10+### SEARCH 
 11+
 12+```
 13+  Returns the position of a text segment within a character string. The start of the search can be set as an option. The search text can be a number or any sequence of characters. The search is not case-sensitive. 
 14+@param findText - The text to be searched for. 
 15+@param withinText - The text where the search will take place 
 16+@param position - [OPTIONAL default 1] The position in the text where the search is to start. 
 17+@constructor
 18+```
 19diff --git a/TODO.md b/TODO.md
 20index f8fd717..a538d01 100644
 21--- a/TODO.md
 22+++ b/TODO.md
 23@@ -47,7 +47,6 @@ Many of these formulas can be written by allowing the Sheet and Parser to return
 24 * REGEXREPLACE - May be difficult considering language differences.
 25 * REPLACE
 26 * REPT
 27-* SEARCH
 28 * SUBSTITUTE
 29 * VALUE
 30 
 31diff --git a/dist/Formulas/AllFormulas.js b/dist/Formulas/AllFormulas.js
 32index 4185998..0131e70 100644
 33--- a/dist/Formulas/AllFormulas.js
 34+++ b/dist/Formulas/AllFormulas.js
 35@@ -232,6 +232,7 @@ exports.JOIN = Text_1.JOIN;
 36 exports.LEN = Text_1.LEN;
 37 exports.LEFT = Text_1.LEFT;
 38 exports.RIGHT = Text_1.RIGHT;
 39+exports.SEARCH = Text_1.SEARCH;
 40 var Date_1 = require("./Date");
 41 exports.DATE = Date_1.DATE;
 42 exports.DATEVALUE = Date_1.DATEVALUE;
 43diff --git a/dist/Formulas/Text.js b/dist/Formulas/Text.js
 44index 3083c85..49ef8da 100644
 45--- a/dist/Formulas/Text.js
 46+++ b/dist/Formulas/Text.js
 47@@ -767,7 +767,7 @@ exports.LEN = LEN;
 48 var LEFT = function (text, numberOfCharacters) {
 49     ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "LEFT");
 50     text = TypeConverter_1.TypeConverter.firstValueAsString(text);
 51-    numberOfCharacters = MoreUtils_1.isUndefined(numberOfCharacters) ? 1 : numberOfCharacters;
 52+    numberOfCharacters = MoreUtils_1.isUndefined(numberOfCharacters) ? 1 : TypeConverter_1.TypeConverter.firstValueAsNumber(numberOfCharacters);
 53     if (numberOfCharacters < 0) {
 54         throw new Errors_1.ValueError("Formula LEFT parameter 2 value is " + numberOfCharacters
 55             + ", but should be greater than or equal to 0.");
 56@@ -786,7 +786,7 @@ exports.LEFT = LEFT;
 57 var RIGHT = function (text, numberOfCharacters) {
 58     ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "RIGHT");
 59     text = TypeConverter_1.TypeConverter.firstValueAsString(text);
 60-    numberOfCharacters = MoreUtils_1.isUndefined(numberOfCharacters) ? 1 : numberOfCharacters;
 61+    numberOfCharacters = MoreUtils_1.isUndefined(numberOfCharacters) ? 1 : TypeConverter_1.TypeConverter.firstValueAsNumber(numberOfCharacters);
 62     if (numberOfCharacters < 0) {
 63         throw new Errors_1.ValueError("Formula RIGHT parameter 2 value is " + numberOfCharacters
 64             + ", but should be greater than or equal to 0.");
 65@@ -794,3 +794,27 @@ var RIGHT = function (text, numberOfCharacters) {
 66     return text.substring(text.length - numberOfCharacters);
 67 };
 68 exports.RIGHT = RIGHT;
 69+/**
 70+ * Returns the position of a text segment within a character string. The start of the search can be set as an option.
 71+ * The search text can be a number or any sequence of characters. The search is not case-sensitive.
 72+ * @param findText - The text to be searched for.
 73+ * @param withinText - The text where the search will take place
 74+ * @param position - [OPTIONAL default 1] The position in the text where the search is to start.
 75+ * @constructor
 76+ */
 77+var SEARCH = function (findText, withinText, position) {
 78+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 2, 3, "SEARCH");
 79+    findText = TypeConverter_1.TypeConverter.firstValueAsString(findText);
 80+    withinText = TypeConverter_1.TypeConverter.firstValueAsString(withinText);
 81+    position = MoreUtils_1.isUndefined(position) ? 0 : TypeConverter_1.TypeConverter.firstValueAsNumber(position);
 82+    if (position < 0) {
 83+        throw new Errors_1.ValueError("Formula SEARCH parameter 3 value is " + position
 84+            + ", but should be greater than or equal to 1.");
 85+    }
 86+    var index = withinText.toLowerCase().indexOf(findText.toLowerCase(), position - 1);
 87+    if (index > -1) {
 88+        return index + 1;
 89+    }
 90+    throw new Errors_1.ValueError("For SEARCH evaluation, cannot find '" + findText + "' inside '" + withinText + "'");
 91+};
 92+exports.SEARCH = SEARCH;
 93diff --git a/src/Formulas/AllFormulas.ts b/src/Formulas/AllFormulas.ts
 94index b2ecbc5..21d62ce 100644
 95--- a/src/Formulas/AllFormulas.ts
 96+++ b/src/Formulas/AllFormulas.ts
 97@@ -239,7 +239,8 @@ import {
 98   JOIN,
 99   LEN,
100   LEFT,
101-  RIGHT
102+  RIGHT,
103+  SEARCH
104 } from "./Text"
105 import {
106   DATE,
107@@ -539,5 +540,6 @@ export {
108   JOIN,
109   LEN,
110   LEFT,
111-  RIGHT
112+  RIGHT,
113+  SEARCH
114 }
115\ No newline at end of file
116diff --git a/src/Formulas/Text.ts b/src/Formulas/Text.ts
117index 8cbbf89..5270124 100644
118--- a/src/Formulas/Text.ts
119+++ b/src/Formulas/Text.ts
120@@ -799,7 +799,7 @@ let LEN = function (value) {
121 let LEFT = function (text, numberOfCharacters?) {
122   ArgsChecker.checkLengthWithin(arguments, 1, 2, "LEFT");
123   text = TypeConverter.firstValueAsString(text);
124-  numberOfCharacters = isUndefined(numberOfCharacters) ? 1 : numberOfCharacters;
125+  numberOfCharacters = isUndefined(numberOfCharacters) ? 1 : TypeConverter.firstValueAsNumber(numberOfCharacters);
126   if (numberOfCharacters < 0) {
127     throw new ValueError("Formula LEFT parameter 2 value is " + numberOfCharacters
128         + ", but should be greater than or equal to 0.");
129@@ -818,7 +818,7 @@ let LEFT = function (text, numberOfCharacters?) {
130 let RIGHT = function (text, numberOfCharacters?) {
131   ArgsChecker.checkLengthWithin(arguments, 1, 2, "RIGHT");
132   text = TypeConverter.firstValueAsString(text);
133-  numberOfCharacters = isUndefined(numberOfCharacters) ? 1 : numberOfCharacters;
134+  numberOfCharacters = isUndefined(numberOfCharacters) ? 1 : TypeConverter.firstValueAsNumber(numberOfCharacters);
135   if (numberOfCharacters < 0) {
136     throw new ValueError("Formula RIGHT parameter 2 value is " + numberOfCharacters
137       + ", but should be greater than or equal to 0.");
138@@ -826,6 +826,30 @@ let RIGHT = function (text, numberOfCharacters?) {
139   return text.substring(text.length - numberOfCharacters);
140 };
141 
142+/**
143+ * Returns the position of a text segment within a character string. The start of the search can be set as an option.
144+ * The search text can be a number or any sequence of characters. The search is not case-sensitive.
145+ * @param findText - The text to be searched for.
146+ * @param withinText - The text where the search will take place
147+ * @param position - [OPTIONAL default 1] The position in the text where the search is to start.
148+ * @constructor
149+ */
150+let SEARCH = function (findText, withinText, position?) {
151+  ArgsChecker.checkLengthWithin(arguments, 2, 3, "SEARCH");
152+  findText = TypeConverter.firstValueAsString(findText);
153+  withinText = TypeConverter.firstValueAsString(withinText);
154+  position = isUndefined(position) ? 0 : TypeConverter.firstValueAsNumber(position);
155+  if (position < 0) {
156+    throw new ValueError("Formula SEARCH parameter 3 value is " + position
157+        + ", but should be greater than or equal to 1.");
158+  }
159+  let index = withinText.toLowerCase().indexOf(findText.toLowerCase(), position - 1);
160+  if (index > -1) {
161+    return index + 1;
162+  }
163+  throw new ValueError("For SEARCH evaluation, cannot find '" + findText + "' inside '" + withinText + "'");
164+};
165+
166 export {
167   ARABIC,
168   CHAR,
169@@ -843,5 +867,6 @@ export {
170   JOIN,
171   LEN,
172   LEFT,
173-  RIGHT
174+  RIGHT,
175+  SEARCH
176 }
177\ No newline at end of file
178diff --git a/tests/Formulas/TextTest.ts b/tests/Formulas/TextTest.ts
179index 7391fcb..05c4c5d 100644
180--- a/tests/Formulas/TextTest.ts
181+++ b/tests/Formulas/TextTest.ts
182@@ -15,7 +15,8 @@ import {
183   JOIN,
184   LEN,
185   LEFT,
186-  RIGHT
187+  RIGHT,
188+  SEARCH
189 } from "../../src/Formulas/Text";
190 import * as ERRORS from "../../src/Errors";
191 import {
192@@ -445,3 +446,24 @@ test("RIGHT", function(){
193     RIGHT.apply(this, [1, 2, 3]);
194   }, ERRORS.NA_ERROR);
195 });
196+
197+test("SEARCH", function(){
198+  assertEquals(SEARCH("soup", "where is the soup?"), 14);
199+  assertEquals(SEARCH("SOUP", "where is the soup?"), 14);
200+  assertEquals(SEARCH("soup", "where Is ThE sOUp?"), 14);
201+  assertEquals(SEARCH("soup", "soup?"), 1);
202+  assertEquals(SEARCH("oup", "soup?"), 2);
203+  assertEquals(SEARCH("soup", "soup, where is the soup?", 14), 20);
204+  catchAndAssertEquals(function() {
205+    SEARCH("beef", "soup?");
206+  }, ERRORS.VALUE_ERROR);
207+  catchAndAssertEquals(function() {
208+    SEARCH("beef", "beef", -10);
209+  }, ERRORS.VALUE_ERROR);
210+  catchAndAssertEquals(function() {
211+    SEARCH.apply(this, [1]);
212+  }, ERRORS.NA_ERROR);
213+  catchAndAssertEquals(function() {
214+    SEARCH.apply(this, [1, 2, 3, 4]);
215+  }, ERRORS.NA_ERROR);
216+});
217diff --git a/tests/SheetFormulaTest.ts b/tests/SheetFormulaTest.ts
218index f209edc..fbebc50 100644
219--- a/tests/SheetFormulaTest.ts
220+++ b/tests/SheetFormulaTest.ts
221@@ -1065,6 +1065,10 @@ test("Sheet RIGHT", function(){
222   assertFormulaEquals('=RIGHT("soup")', "p");
223 });
224 
225+test("Sheet SEARCH", function(){
226+  assertFormulaEquals('=SEARCH("soup", "soup?")', 1);
227+});
228+
229 test("Sheet parsing error", function(){
230   assertFormulaEqualsError('= 10e', PARSE_ERROR);
231   assertFormulaEqualsError('= SUM(', PARSE_ERROR);