Permalink
Browse files

added XRegExp.replaceEach for batch replacements. named by @kriskowal.

…closes #20
  • Loading branch information...
1 parent f03f3eb commit 018f423686f445ffedd55f62bc237900171a1d32 @slevithan committed Jun 9, 2012
Showing with 101 additions and 13 deletions.
  1. +1 −1 package.json
  2. +33 −1 src/xregexp.js
  3. +34 −10 tests/tests.js
  4. +33 −1 xregexp-all.js
View
@@ -1,6 +1,6 @@
{
"name": "xregexp",
- "version": "2.0.0",
+ "version": "2.1.0-dev",
"homepage": "http://xregexp.com/",
"author": "Steven Levithan <steves_list@hotmail.com>",
"license": "MIT",
View
@@ -741,7 +741,7 @@ XRegExp = XRegExp || (function (undef) {
* });
* // -> 'Smith, John'
*
- * // Global string search/replacement
+ * // String search, with replace-all
* XRegExp.replace('RegExp builds RegExps', 'RegExp', 'XRegExp', 'all');
* // -> 'XRegExp builds XRegExps'
*/
@@ -772,6 +772,38 @@ XRegExp = XRegExp || (function (undef) {
};
/**
+ * Performs batch processing of string replacements. Used like {@link #XRegExp.replace}, but
+ * accepts an array of replacement details. Later replacements operate on the output of earlier
+ * replacements. Replacement details are accepted as an array with a regex or string to search for,
+ * the replacement string or function, and an optional scope of 'one' or 'all'. Uses the XRegExp
+ * replacement text syntax, which supports named backreference properties via `${name}`.
+ * @memberOf XRegExp
+ * @param {String} str String to search.
+ * @param {Array} replacements Array of replacement detail arrays.
+ * @returns {String} New string with all replacements.
+ * @example
+ *
+ * str = XRegExp.replaceEach(str, [
+ * [XRegExp('(?<name>a)'), 'z${name}'],
+ * [/b/gi, 'y'],
+ * [/c/g, 'x', 'one'], // scope 'one' overrides /g
+ * [/d/, 'w', 'all'], // scope 'all' overrides lack of /g
+ * ['e', 'v', 'all'], // scope 'all' allows replace-all for strings
+ * [/f/g, function ($0) {
+ * return $0.toUpperCase();
+ * }]
+ * ]);
+ */
+ self.replaceEach = function (str, replacements) {
+ var i, r;
+ for (i = 0; i < replacements.length; ++i) {
+ r = replacements[i];
+ str = self.replace(str, r[0], r[1], r[2]);
+ }
+ return str;
+ };
+
+/**
* Splits a string into an array of strings using a regex or string separator. Matches of the
* separator are not included in the result array. However, if `separator` is a regex that contains
* capturing groups, backreferences are spliced into the result each time `separator` is matched.
View
@@ -26,6 +26,7 @@ test("Basic availability", function () {
ok(XRegExp.isRegExp, "XRegExp.isRegExp exists");
ok(XRegExp.matchChain, "XRegExp.matchChain exists");
ok(XRegExp.replace, "XRegExp.replace exists");
+ ok(XRegExp.replaceEach, "XRegExp.replaceEach exists");
ok(XRegExp.split, "XRegExp.split exists");
ok(XRegExp.test, "XRegExp.test exists");
ok(XRegExp.uninstall, "XRegExp.uninstall exists");
@@ -276,19 +277,41 @@ test("XRegExp.matchChain", function () {
});
test("XRegExp.replace", function () {
- equal(XRegExp.replace("test", "t", "x", "all"), "xesx", "string search with scope='all'");
- equal(XRegExp.replace("test", "t", "x", "one"), "xest", "string search with scope='one'");
- equal(XRegExp.replace("test", "t", "x"), "xest", "string search without scope");
- equal(XRegExp.replace("test", /t/, "x", "all"), "xesx", "regex search with scope='all'");
- equal(XRegExp.replace("test", /t/, "x", "one"), "xest", "regex search with scope='one'");
- equal(XRegExp.replace("test", /t/, "x"), "xest", "regex search without scope");
- equal(XRegExp.replace("test", /t/g, "x", "all"), "xesx", "global regex search with scope='all'");
- equal(XRegExp.replace("test", /t/g, "x", "one"), "xest", "global regex search with scope='one'");
- equal(XRegExp.replace("test", /t/g, "x"), "xesx", "global regex search without scope");
+ equal(XRegExp.replace("test", "t", "x", "all"), "xesx", "String search with scope='all'");
+ equal(XRegExp.replace("test", "t", "x", "one"), "xest", "String search with scope='one'");
+ equal(XRegExp.replace("test", "t", "x"), "xest", "String search without scope");
+ equal(XRegExp.replace("test", /t/, "x", "all"), "xesx", "Regex search with scope='all'");
+ equal(XRegExp.replace("test", /t/, "x", "one"), "xest", "Regex search with scope='one'");
+ equal(XRegExp.replace("test", /t/, "x"), "xest", "Regex search without scope");
+ equal(XRegExp.replace("test", /t/g, "x", "all"), "xesx", "Global regex search with scope='all'");
+ equal(XRegExp.replace("test", /t/g, "x", "one"), "xest", "Global regex search with scope='one'");
+ equal(XRegExp.replace("test", /t/g, "x"), "xesx", "Global regex search without scope");
// TODO: Add tests (above tests cover scope functionality only)
});
+test("XRegExp.replaceEach", function () {
+ equal(XRegExp.replaceEach("aabBccddeeffgghh", [
+ [XRegExp("(?<name>a)"), "z${name}"],
+ [/b/gi, "y"],
+ [/c/g, "x", "one"],
+ [/d/, "w", "all"],
+ ["e", "v", "all"],
+ [/f/g, function ($0) {return $0.toUpperCase();}],
+ ["g", function ($0) {return $0.toUpperCase();}],
+ ["h", function ($0) {return $0.toUpperCase();}, "all"]
+ ]), "zaayyxcwwvvFFGgHH", "All basic search/replacement types and scopes");
+
+ equal(XRegExp.replaceEach("<&>", [
+ [/&/g, "&amp;"],
+ [/</g, "&lt;"],
+ [/a/g, "b"],
+ [/b/g, "c"]
+ ]), "&lt;&cmp;>", "Search string is output of prior replacements");
+
+ // TODO: Add tests
+});
+
test("XRegExp.split", function () {
expect(0);
// TODO: Add tests
@@ -778,7 +801,8 @@ module("Addons");
//-------------------------------------------------------------------
test("Unicode base", function () {
- expect(0);
+ ok(XRegExp.addUnicodePackage, "XRegExp.addUnicodePackage exists");
+
// TODO: Add tests
});
View
@@ -744,7 +744,7 @@ XRegExp = XRegExp || (function (undef) {
* });
* // -> 'Smith, John'
*
- * // Global string search/replacement
+ * // String search, with replace-all
* XRegExp.replace('RegExp builds RegExps', 'RegExp', 'XRegExp', 'all');
* // -> 'XRegExp builds XRegExps'
*/
@@ -775,6 +775,38 @@ XRegExp = XRegExp || (function (undef) {
};
/**
+ * Performs batch processing of string replacements. Used like {@link #XRegExp.replace}, but
+ * accepts an array of replacement details. Later replacements operate on the output of earlier
+ * replacements. Replacement details are accepted as an array with a regex or string to search for,
+ * the replacement string or function, and an optional scope of 'one' or 'all'. Uses the XRegExp
+ * replacement text syntax, which supports named backreference properties via `${name}`.
+ * @memberOf XRegExp
+ * @param {String} str String to search.
+ * @param {Array} replacements Array of replacement detail arrays.
+ * @returns {String} New string with all replacements.
+ * @example
+ *
+ * str = XRegExp.replaceEach(str, [
+ * [XRegExp('(?<name>a)'), 'z${name}'],
+ * [/b/gi, 'y'],
+ * [/c/g, 'x', 'one'], // scope 'one' overrides /g
+ * [/d/, 'w', 'all'], // scope 'all' overrides lack of /g
+ * ['e', 'v', 'all'], // scope 'all' allows replace-all for strings
+ * [/f/g, function ($0) {
+ * return $0.toUpperCase();
+ * }]
+ * ]);
+ */
+ self.replaceEach = function (str, replacements) {
+ var i, r;
+ for (i = 0; i < replacements.length; ++i) {
+ r = replacements[i];
+ str = self.replace(str, r[0], r[1], r[2]);
+ }
+ return str;
+ };
+
+/**
* Splits a string into an array of strings using a regex or string separator. Matches of the
* separator are not included in the result array. However, if `separator` is a regex that contains
* capturing groups, backreferences are spliced into the result each time `separator` is matched.

0 comments on commit 018f423

Please sign in to comment.