spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
[Text.SUBSTITUTE] formula added and tested
author
Ben Vogt <[email protected]>
date
2017-12-01 04:50:02
stats
8 file(s) changed, 114 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 5777d37..f04a23c 100644
  3--- a/DOCS.md
  4+++ b/DOCS.md
  5@@ -2510,3 +2510,15 @@
  6 @param newText - The text which replaces text. 
  7 @constructor
  8 ```
  9+
 10+### SUBSTITUTE 
 11+
 12+```
 13+  Substitutes new text for old text in a string. 
 14+@param text - The text in which text segments are to be exchanged. 
 15+@param searchFor - The text segment that is to be replaced (a number of times) 
 16+@param replaceWith - The text that is to replace the text segment. 
 17+@param occurrence - [OPTIONAL] - Indicates how many occurrences of the search text are to be replaced. If this parameter is missing, the search text is replaced throughout. 
 18+@returns {string} 
 19+@constructor
 20+```
 21diff --git a/TODO.md b/TODO.md
 22index c608205..00fc034 100644
 23--- a/TODO.md
 24+++ b/TODO.md
 25@@ -46,7 +46,6 @@ Many of these formulas can be written by allowing the Sheet and Parser to return
 26 * REGEXEXTRACT - May be difficult considering language differences.
 27 * REGEXMATCH - May be difficult considering language differences.
 28 * REGEXREPLACE - May be difficult considering language differences.
 29-* SUBSTITUTE
 30 
 31 ### Other formulas to write
 32 * CRITBINOM
 33diff --git a/dist/Formulas/AllFormulas.js b/dist/Formulas/AllFormulas.js
 34index 0a7ac0d..a041956 100644
 35--- a/dist/Formulas/AllFormulas.js
 36+++ b/dist/Formulas/AllFormulas.js
 37@@ -239,6 +239,7 @@ exports.CLEAN = Text_1.CLEAN;
 38 exports.MID = Text_1.MID;
 39 exports.PROPER = Text_1.PROPER;
 40 exports.REPLACE = Text_1.REPLACE;
 41+exports.SUBSTITUTE = Text_1.SUBSTITUTE;
 42 var Date_1 = require("./Date");
 43 exports.DATE = Date_1.DATE;
 44 exports.DATEVALUE = Date_1.DATEVALUE;
 45diff --git a/dist/Formulas/Text.js b/dist/Formulas/Text.js
 46index d1401d0..141bd6c 100644
 47--- a/dist/Formulas/Text.js
 48+++ b/dist/Formulas/Text.js
 49@@ -922,3 +922,38 @@ var REPLACE = function (text, position, length, newText) {
 50     return text.substr(0, position - 1) + newText + text.substr(position - 1 + length);
 51 };
 52 exports.REPLACE = REPLACE;
 53+/**
 54+ * Substitutes new text for old text in a string.
 55+ * @param text - The text in which text segments are to be exchanged.
 56+ * @param searchFor - The text segment that is to be replaced (a number of times)
 57+ * @param replaceWith - The text that is to replace the text segment.
 58+ * @param occurrence - [OPTIONAL] - Indicates how many occurrences of the search text are to be replaced. If this
 59+ * parameter is missing, the search text is replaced throughout.
 60+ * @returns {string}
 61+ * @constructor
 62+ */
 63+var SUBSTITUTE = function (text, searchFor, replaceWith, occurrence) {
 64+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 3, 4, "SUBSTITUTE");
 65+    text = TypeConverter_1.TypeConverter.firstValueAsString(text);
 66+    searchFor = TypeConverter_1.TypeConverter.firstValueAsString(searchFor);
 67+    replaceWith = TypeConverter_1.TypeConverter.firstValueAsString(replaceWith);
 68+    if (MoreUtils_1.isUndefined(occurrence)) {
 69+        return text.replace(new RegExp(searchFor, 'g'), replaceWith);
 70+    }
 71+    occurrence = TypeConverter_1.TypeConverter.firstValueAsNumber(occurrence);
 72+    if (occurrence < 0) {
 73+        throw new Errors_1.ValueError("Function SUBSTITUTE parameter 4 value is " + occurrence
 74+            + ", but should be greater than or equal to 0.");
 75+    }
 76+    var index = 0;
 77+    var i = 0;
 78+    while (text.indexOf(searchFor, index) > -1) {
 79+        index = text.indexOf(searchFor, index);
 80+        i++;
 81+        if (i === occurrence) {
 82+            return text.substring(0, index) + replaceWith + text.substring(index + searchFor.length);
 83+        }
 84+    }
 85+    return text;
 86+};
 87+exports.SUBSTITUTE = SUBSTITUTE;
 88diff --git a/src/Formulas/AllFormulas.ts b/src/Formulas/AllFormulas.ts
 89index cdc6fc1..5305cb9 100644
 90--- a/src/Formulas/AllFormulas.ts
 91+++ b/src/Formulas/AllFormulas.ts
 92@@ -246,7 +246,8 @@ import {
 93   CLEAN,
 94   MID,
 95   PROPER,
 96-  REPLACE
 97+  REPLACE,
 98+  SUBSTITUTE
 99 } from "./Text"
100 import {
101   DATE,
102@@ -553,5 +554,6 @@ export {
103   CLEAN,
104   MID,
105   PROPER,
106-  REPLACE
107+  REPLACE,
108+  SUBSTITUTE
109 }
110\ No newline at end of file
111diff --git a/src/Formulas/Text.ts b/src/Formulas/Text.ts
112index a1f1e96..80db805 100644
113--- a/src/Formulas/Text.ts
114+++ b/src/Formulas/Text.ts
115@@ -956,6 +956,43 @@ let REPLACE = function (text, position, length, newText) {
116   return text.substr(0, position - 1) + newText + text.substr(position - 1 + length);
117 };
118 
119+
120+/**
121+ * Substitutes new text for old text in a string.
122+ * @param text - The text in which text segments are to be exchanged.
123+ * @param searchFor - The text segment that is to be replaced (a number of times)
124+ * @param replaceWith - The text that is to replace the text segment.
125+ * @param occurrence - [OPTIONAL] - Indicates how many occurrences of the search text are to be replaced. If this
126+ * parameter is missing, the search text is replaced throughout.
127+ * @returns {string}
128+ * @constructor
129+ */
130+let SUBSTITUTE = function (text, searchFor, replaceWith, occurrence?) {
131+  ArgsChecker.checkLengthWithin(arguments, 3, 4, "SUBSTITUTE");
132+  text = TypeConverter.firstValueAsString(text);
133+  searchFor = TypeConverter.firstValueAsString(searchFor);
134+  replaceWith = TypeConverter.firstValueAsString(replaceWith);
135+
136+  if (isUndefined(occurrence)) {
137+    return text.replace(new RegExp(searchFor, 'g'), replaceWith);
138+  }
139+  occurrence = TypeConverter.firstValueAsNumber(occurrence);
140+  if (occurrence < 0) {
141+    throw new ValueError("Function SUBSTITUTE parameter 4 value is " + occurrence
142+        + ", but should be greater than or equal to 0.");
143+  }
144+  let index = 0;
145+  let i = 0;
146+  while (text.indexOf(searchFor, index) > -1) {
147+    index = text.indexOf(searchFor, index);
148+    i++;
149+    if (i === occurrence) {
150+      return text.substring(0, index) + replaceWith + text.substring(index + searchFor.length);
151+    }
152+  }
153+  return text;
154+};
155+
156 export {
157   ARABIC,
158   CHAR,
159@@ -980,5 +1017,6 @@ export {
160   CLEAN,
161   MID,
162   PROPER,
163-  REPLACE
164+  REPLACE,
165+  SUBSTITUTE
166 }
167\ No newline at end of file
168diff --git a/tests/Formulas/TextTest.ts b/tests/Formulas/TextTest.ts
169index dc8ebc1..b0b5441 100644
170--- a/tests/Formulas/TextTest.ts
171+++ b/tests/Formulas/TextTest.ts
172@@ -22,7 +22,8 @@ import {
173   CLEAN,
174   MID,
175   PROPER,
176-  REPLACE
177+  REPLACE,
178+  SUBSTITUTE
179 } from "../../src/Formulas/Text";
180 import * as ERRORS from "../../src/Errors";
181 import {
182@@ -574,3 +575,18 @@ test("PROPER", function(){
183     REPLACE("Hey there", 1, -1, "Hello")
184   }, ERRORS.VALUE_ERROR);
185 });
186+
187+test("SUBSTITUTE", function(){
188+  assertEquals(SUBSTITUTE("Hey darkness my old friend", "Hey", "Hello"), "Hello darkness my old friend");
189+  assertEquals(SUBSTITUTE("Hey darkness my old friend... Hey.", "Hey", "Hello"), "Hello darkness my old friend... Hello.");
190+  assertEquals(SUBSTITUTE("Hey darkness my old friend... Hey.", "Hey", "Hello", 1), "Hello darkness my old friend... Hey.");
191+  catchAndAssertEquals(function () {
192+    SUBSTITUTE.apply(this, ["a", "b"]);
193+  }, ERRORS.NA_ERROR);
194+  catchAndAssertEquals(function () {
195+    SUBSTITUTE.apply(this, ["a", "b", "c", 1, 2]);
196+  }, ERRORS.NA_ERROR);
197+  catchAndAssertEquals(function () {
198+    SUBSTITUTE("Hey there", "hey", "hello", -1);
199+  }, ERRORS.VALUE_ERROR);
200+});
201diff --git a/tests/SheetFormulaTest.ts b/tests/SheetFormulaTest.ts
202index 1d943f0..bcaa3ef 100644
203--- a/tests/SheetFormulaTest.ts
204+++ b/tests/SheetFormulaTest.ts
205@@ -1089,10 +1089,14 @@ test("Sheet PROPER", function(){
206   assertFormulaEquals('=PROPER("hey there")', "Hey There");
207 });
208 
209-test("Sheet PROPER", function(){
210+test("Sheet REPLACE", function(){
211   assertFormulaEquals('=REPLACE("Hey there", 1, 3, "Hello")', "Hello there");
212 });
213 
214+test("Sheet SUBSTITUTE", function(){
215+  assertFormulaEquals('=SUBSTITUTE("Hey darkness my old friend", "Hey", "Hello")', "Hello darkness my old friend");
216+});
217+
218 test("Sheet parsing error", function(){
219   assertFormulaEqualsError('= 10e', PARSE_ERROR);
220   assertFormulaEqualsError('= SUM(', PARSE_ERROR);