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);