spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
[Text.FIND] formula added and tested
author
Ben Vogt <[email protected]>
date
2017-10-08 00:06:58
stats
8 file(s) changed, 99 insertions(+), 6 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 4a2593e..3ac35be 100644
  3--- a/DOCS.md
  4+++ b/DOCS.md
  5@@ -2402,3 +2402,14 @@
  6 @param format - Text which defines the format. "0" forces the display of zeros, while "#" suppresses the display of zeros. For example TEXT(22.1,"000.00") produces 022.10, while TEXT(22.1,"###.##") produces 22.1, and TEXT(22.405,"00.00") results in 22.41. To format days: "dddd" indicates full name of the day of the week, "ddd" hort name of the day of the week, "dd" indicates the day of the month as two digits, "d" indicates day of the month as one or two digits, "mmmmm" indicates the first letter in the month of the year, "mmmm" indicates the full name of the month of the year, "mmm" indicates short name of the month of the year, "mm" indicates month of the year as two digits or the number of minutes in a time, depending on whether it follows yy or dd, or if it follows hh, "m" month of the year as one or two digits or the number of minutes in a time, depending on whether it follows yy or dd, or if it follows hh, "yyyy" indicates year as four digits, "yy" and "y" indicate year as two digits, "hh" indicates hour on a 24-hour clock, "h" indicates hour on a 12-hour clock, "ss.000" indicates milliseconds in a time, "ss" indicates econds in a time, "AM/PM" or "A/P" indicate displaying hours based on a 12-hour clock and showing AM or PM depending on the time of day. Eg: `TEXT("01/09/2012 10:04:33AM", "mmmm-dd-yyyy, hh:mm AM/PM")` would result in "January-09-2012, 10:04 AM".  
  7 @constructor if (format.match(/^.(d|D|M|m|yy|Y|HH|hh|h|s|S|AM|PM|am|pm|A\/P|\).$/g)) { const POUND_SIGN_FORMAT_CAPTURE = /^([$
  8 ```
  9+
 10+### FIND 
 11+
 12+```
 13+  Looks for a string of text within another string. Where to begin the search can also be defined. The search term can be a number or any string of characters. The search is case-sensitive. 
 14+@param searchFor - The text to be found. 
 15+@param searchIn - The text where the search takes place. 
 16+@param startAt - [OPTIONAL defaults to 1] - The position in the text from which the search starts. 
 17+@returns {number} 
 18+@constructor
 19+```
 20diff --git a/TODO.md b/TODO.md
 21index cdc319e..49b421e 100644
 22--- a/TODO.md
 23+++ b/TODO.md
 24@@ -40,7 +40,6 @@ Many of these formulas can be written by allowing the Sheet and Parser to return
 25 
 26 ### Easy formulas to write
 27 * CLEAN
 28-* FIND
 29 * JOIN
 30 * LEFT
 31 * LEN
 32diff --git a/dist/Formulas/AllFormulas.js b/dist/Formulas/AllFormulas.js
 33index 507582a..3326bf4 100644
 34--- a/dist/Formulas/AllFormulas.js
 35+++ b/dist/Formulas/AllFormulas.js
 36@@ -227,6 +227,7 @@ exports.UPPER = Text_1.UPPER;
 37 exports.T = Text_1.T;
 38 exports.ROMAN = Text_1.ROMAN;
 39 exports.TEXT = Text_1.TEXT;
 40+exports.FIND = Text_1.FIND;
 41 var Date_1 = require("./Date");
 42 exports.DATE = Date_1.DATE;
 43 exports.DATEVALUE = Date_1.DATEVALUE;
 44diff --git a/dist/Formulas/Text.js b/dist/Formulas/Text.js
 45index 790ba46..e3e9833 100644
 46--- a/dist/Formulas/Text.js
 47+++ b/dist/Formulas/Text.js
 48@@ -703,3 +703,27 @@ var TEXT = function (value, format) {
 49     }
 50 };
 51 exports.TEXT = TEXT;
 52+/**
 53+ * Looks for a string of text within another string. Where to begin the search can also be defined. The search term can
 54+ * be a number or any string of characters. The search is case-sensitive.
 55+ * @param searchFor - The text to be found.
 56+ * @param searchIn - The text where the search takes place.
 57+ * @param startAt - [OPTIONAL defaults to 1] - The position in the text from which the search starts.
 58+ * @returns {number}
 59+ * @constructor
 60+ */
 61+var FIND = function (searchFor, searchIn, startAt) {
 62+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 2, 3, "FIND");
 63+    searchFor = TypeConverter_1.TypeConverter.firstValueAsString(searchFor);
 64+    searchIn = TypeConverter_1.TypeConverter.firstValueAsString(searchIn);
 65+    startAt = MoreUtils_1.isUndefined(startAt) ? 1 : TypeConverter_1.TypeConverter.firstValueAsNumber(startAt);
 66+    if (startAt < 1) {
 67+        throw new Errors_1.ValueError("FIND parameter 3 value is " + startAt + ", but should be greater than or equal to 1.");
 68+    }
 69+    var index = searchIn.indexOf(searchFor, startAt - 1);
 70+    if (index > -1) {
 71+        return index + 1;
 72+    }
 73+    throw new Errors_1.ValueError("For FIND cannot find '" + searchFor + "' within '" + searchIn + "'.");
 74+};
 75+exports.FIND = FIND;
 76diff --git a/src/Formulas/AllFormulas.ts b/src/Formulas/AllFormulas.ts
 77index 31b36ed..ab5ad6c 100644
 78--- a/src/Formulas/AllFormulas.ts
 79+++ b/src/Formulas/AllFormulas.ts
 80@@ -234,7 +234,8 @@ import {
 81   UPPER,
 82   T,
 83   ROMAN,
 84-  TEXT
 85+  TEXT,
 86+  FIND
 87 } from "./Text"
 88 import {
 89   DATE,
 90@@ -529,5 +530,6 @@ export {
 91   RATE,
 92   SUBTOTAL,
 93   HYPGEOMDIST,
 94-  ZTEST
 95+  ZTEST,
 96+  FIND
 97 }
 98\ No newline at end of file
 99diff --git a/src/Formulas/Text.ts b/src/Formulas/Text.ts
100index 04c9334..6a68e4f 100644
101--- a/src/Formulas/Text.ts
102+++ b/src/Formulas/Text.ts
103@@ -14,7 +14,7 @@ import {
104   Filter
105 } from "../Utilities/Filter";
106 import {
107-  isDefined,
108+  isDefined, isUndefined,
109   NumberStringBuilder
110 } from "../Utilities/MoreUtils";
111 import {ROUND} from "./Math";
112@@ -739,6 +739,30 @@ let TEXT = function (value, format) {
113   }
114 };
115 
116+/**
117+ * Looks for a string of text within another string. Where to begin the search can also be defined. The search term can
118+ * be a number or any string of characters. The search is case-sensitive.
119+ * @param searchFor - The text to be found.
120+ * @param searchIn - The text where the search takes place.
121+ * @param startAt - [OPTIONAL defaults to 1] - The position in the text from which the search starts.
122+ * @returns {number}
123+ * @constructor
124+ */
125+let FIND = function (searchFor, searchIn, startAt?) {
126+  ArgsChecker.checkLengthWithin(arguments, 2, 3, "FIND");
127+  searchFor = TypeConverter.firstValueAsString(searchFor);
128+  searchIn = TypeConverter.firstValueAsString(searchIn);
129+  startAt = isUndefined(startAt) ? 1 : TypeConverter.firstValueAsNumber(startAt);
130+  if (startAt < 1) {
131+    throw new ValueError("FIND parameter 3 value is " + startAt + ", but should be greater than or equal to 1.");
132+  }
133+  let index = searchIn.indexOf(searchFor, startAt - 1);
134+  if (index > -1) {
135+    return index + 1;
136+  }
137+  throw new ValueError("For FIND cannot find '" + searchFor + "' within '" + searchIn + "'.");
138+};
139+
140 export {
141   ARABIC,
142   CHAR,
143@@ -751,5 +775,6 @@ export {
144   UPPER,
145   T,
146   ROMAN,
147-  TEXT
148+  TEXT,
149+  FIND
150 }
151\ No newline at end of file
152diff --git a/tests/Formulas/TextTest.ts b/tests/Formulas/TextTest.ts
153index 8bb2e19..79282a6 100644
154--- a/tests/Formulas/TextTest.ts
155+++ b/tests/Formulas/TextTest.ts
156@@ -10,7 +10,8 @@ import {
157   UPPER,
158   T,
159   ROMAN,
160-  TEXT
161+  TEXT,
162+  FIND
163 } from "../../src/Formulas/Text";
164 import * as ERRORS from "../../src/Errors";
165 import {
166@@ -349,3 +350,28 @@ test("TEXT", function(){
167     TEXT.apply(this, [100, "0", 10])
168   }, ERRORS.NA_ERROR);
169 });
170+
171+test("FIND", function(){
172+  assertEquals(FIND("s", "soup", 1), 1);
173+  assertEquals(FIND("s", "soup"), 1);
174+  assertEquals(FIND("o", "soup"), 2);
175+  assertEquals(FIND("u", "soup"), 3);
176+  assertEquals(FIND("p", "soup"), 4);
177+  assertEquals(FIND("s", "soup soup", 5), 6);
178+  assertEquals(FIND("o", "soup soup", 5), 7);
179+  assertEquals(FIND("u", "soup soup", 5), 8);
180+  assertEquals(FIND("p", "soup soup", 5), 9);
181+  assertEquals(FIND("p", "soup soup", 4), 4);
182+  catchAndAssertEquals(function() {
183+    FIND("m", "soup", -1);
184+  }, ERRORS.VALUE_ERROR);
185+  catchAndAssertEquals(function() {
186+    FIND("m", "soup");
187+  }, ERRORS.VALUE_ERROR);
188+  catchAndAssertEquals(function() {
189+    FIND.apply(this, [2])
190+  }, ERRORS.NA_ERROR);
191+  catchAndAssertEquals(function() {
192+    FIND.apply(this, [2, 3, 4, 5])
193+  }, ERRORS.NA_ERROR);
194+});
195diff --git a/tests/SheetFormulaTest.ts b/tests/SheetFormulaTest.ts
196index 65f485c..35416e6 100644
197--- a/tests/SheetFormulaTest.ts
198+++ b/tests/SheetFormulaTest.ts
199@@ -1045,6 +1045,10 @@ test("Sheet ZTEST", function(){
200   assertFormulaEquals('=ZTEST([1, 2, 3, 4, 5, 6, 7], 5.6, 1.1)', 0.9999405457342111);
201 });
202 
203+test("Sheet FIND", function(){
204+  assertFormulaEquals('=FIND("s", "soup")', 1);
205+});
206+
207 test("Sheet parsing error", function(){
208   assertFormulaEqualsError('= 10e', PARSE_ERROR);
209   assertFormulaEqualsError('= SUM(', PARSE_ERROR);