How to pass a RegEx backreferences as a variable? - javascript

I'm trying to pass the backreferences to a dynamically-created-function as a variable (so i could check if the backreferences is set and if not throw an error) but i can't find a solution for passing it. How can you make it work???
This is the code:
class regexMap {
constructor(map) {
this.map = map;
}
replace(str){
for (var i = 0; i < this.map.length; i++){
var regexp = new RegExp(this.map[i][0], 'ig');
str = str.replace(regexp, this.map[i][1].apply(this));
}
return str;
}
}
// EXAMPLE:
var map = [
[/FIND (.*)/g,function(){
var br = '$1'; // Don't work.
if(br != '' && br != undefined){
return 'find(\'$1\');'
} else {
console.error('Find requires a string');
return;
}
}],
];
console.log(new regexMap(map).replace("FIND This is a string\nFIND "));
Thanks!

The fucntion you pass into replace will receive the full match as its first argument and then additional arguments containing the contents of capture groups. So you can declare those in your function, then use the function directly in your regexMap#replace method. See *** comments:
class regexMap {
constructor(map) {
this.map = map;
}
replace(str){
for (var i = 0; i < this.map.length; i++){
var regexp = new RegExp(this.map[i][0], 'ig');
str = str.replace(regexp, this.map[i][1].bind(this)); // ***
}
return str;
}
}
// EXAMPLE:
var map = [
[/FIND (.*)/g,function(m, br){ // ***
if(br != '' && br != undefined){
return 'find(\'' + br + '\');'
} else {
console.error('Find requires a string');
return;
}
}],
];
console.log(new regexMap(map).replace("FIND This is a string\nFIND "));

Related

Javascript issue with precedence

I have built this function to replace a group of characters in a string by a random value from another list within a function:
function replaceExpr(a) {
var expToReplace = 0
var newSent = a
while (expToReplace == 0) {
if (a.search("zx") == -1) {
expToReplace = 1
} else {
var startPos = a.search("zx");
startPos += 2;
var endPos = a.search("xz");
var b = a.substring(startPos, endPos);
var fn = window[b];
if (typeof fn === "function") var newWord = fn();
final = newSent.replace("zx" + b + "xz", newWord);
newSent = final
a = a.replace("zx" + b + "xz", "")
}
}
return final
}
function appearance() {
var list = [
"attractive",
"fit",
"handsome",
"plain",
"short",
"tall",
"skinny",
"well-built",
"unkempt",
"unattractive"
]
return list[Math.floor(Math.random() * list.length)];
}
function personality() {
var list = [
"aggresive",
"absent-minded",
"cautious",
"detached from the real world",
"easygoing",
"focused",
"honest",
"dishonest",
"polite",
"uncivilized"
]
return list[Math.floor(Math.random() * list.length)];
}
An example :
var a = replaceExpr("Theodor is a zxappearancexz man. He seems rather zxpersonalityxz.")
alert(a)
// Theodor is a unattractive man. He seems rather cautious.
Everything works perfectly with the function but I have an issue related to it. As you can see, there's one grammar mistake : it's written "a unattractive" where it should be "an unattractive".
There's a function I usually use to to fix the a\an issue which is :
var AvsAnSimple = (function (root) {
//by Eamon Nerbonne (from http://home.nerbonne.org/A-vs-An), Apache 2.0 license
// finds if a word needs a "a" or "an" before it
var dict = "2h.#2.a;i;&1.N;*4.a;e;i;o;/9.a;e;h1.o.i;l1./;n1.o.o;r1.e.s1./;01.8;12.1a;01.0;12.8;9;2.31.7;4.5.6.7.8.9.8a;0a.0;1;2;3;4;5;6;7;8;9;11; .22; .–.31; .42; .–.55; .,.h.k.m.62; .k.72; .–.82; .,.92; .–.8;<2.m1.d;o;=1.=1.E;#;A6;A1;A1.S;i1;r1;o.m1;a1;r1; .n1;d1;a1;l1;u1;c1.i1.a1.n;s1;t1;u1;r1;i1;a1;s.t1;h1;l1;e1;t1;e1.s;B2.h2.a1.i1;r1;a.á;o1.r1.d1. ;C3.a1.i1.s1.s.h4.a2.i1.s1;e.o1.i;l1.á;r1.o1.í;u2.i;r1.r1.a;o1.n1.g1.j;D7.a1.o1.q;i2.n1.a1.s;o1.t;u1.a1.l1.c;á1. ;ò;ù;ư;E7;U1;R.b1;o1;l1;i.m1;p1;e1;z.n1;a1;m.s1;p5.a1.c;e;h;o;r;u1.l1;o.w1;i.F11. ;,;.;/;0;1;2;3;4;5;6;71.0.8;9;Ae;B.C.D.F.I2.L.R.K.L.M.N.P.Q.R.S.T.B;C1;M.D;E2.C;I;F1;r.H;I3.A1;T.R1. ;U;J;L3.C;N;P;M;O1. ;P1;..R2.A1. ;S;S;T1;S.U2.,;.;X;Y1;V.c;f1.o.h;σ;G7.e1.r1.n1.e;h1.a3.e;i;o;i1.a1.n1.g;o2.f1. ;t1.t1. ;r1.i1.a;w1.a1.r1.r;ú;Hs. ;&;,;.2;A.I.1;2;3;5;7;B1;P.C;D;F;G;H1;I.I6;C.G.N.P.S1.D;T.K1.9;L;M1;..N;O2. ;V;P;R1;T.S1.F.T;V;e2.i1.r;r1.r1.n;o2.n6;d.e1.s;g.k.o2;l.r1;i1.f;v.u1.r;I3;I2;*.I.n1;d1;e1;p1;e1;n1;d2;e1;n1;c1;i.ê.s1;l1;a1;n1;d1;s.J1.i1.a1.o;Ly. ;,;.;1;2;3;4;8;A3. ;P;X;B;C;D;E2. ;D;F1;T.G;H1.D.I1.R;L;M;N;P;R;S1;m.T;U1. ;V1;C.W1.T;Z;^;a1.o1.i1.g;o1.c1.h1.a1;b.p;u1.s1.h1;o.ộ;M15. ;&;,;.1;A1;.1;S./;1;2;3;4;5;6;7;8;Ai;B.C.D.F.G.J.L.M.N.P.R.S.T.V.W.X.Y.Z.B1;S1;T.C;D;E3.P1;S.W;n;F;G;H;I4. ;5;6;T1;M.K;L;M;N;O1.U;P;Q;R;S;T1;R.U2. ;V;V;X;b1.u1.m;f;h;o2.D1.e.U1;..p1.3;s1.c;Ny. ;+;.1.E.4;7;8;:;A3.A1;F.I;S1.L;B;C;D;E3.A;H;S1. ;F1;U.G;H;I7.C.D1. ;K.L.N.O.S.K;L;M1;M.N2.R;T;P1.O1.V1./1.B;R2;J.T.S1;W.T1;L1.D.U1.S;V;W2.A;O1.H;X;Y3.C1.L;P;U;a1.s1.a1.n;t1.h;v;²;×;O5;N1;E.l1;v.n2;c1.e.e1.i;o1;p.u1;i.P1.h2.i1.a;o2.b2;i.o.i;Q1.i1.n1.g1.x;Rz. ;&;,;.1;J./;1;4;6;A3. ;.;F1;T.B1;R.C;D;E3. ;S1.P;U;F;G;H1.S;I2.A;C1. ;J;K;L1;P.M5;1.2.3.5.6.N;O2.H;T2;A.O.P;Q;R1;F.S4;,...?.T.T;U4;B.M.N.S.V;X;c;f1;M1...h2.A;B;ò;S11. ;&;,;.4.E;M;O;T1..3.B;D;M;1;3;4;5;6;8;9;A3. ;8;S2;E.I.B;C3.A1. ;R2.A.U.T;D;E6. ;5;C3;A.O.R.I1.F.O;U;F3;&.H.O1.S.G1;D.H3.2;3;L;I2. ;S1.O.K2.I.Y.L3;A2. ;.;I1. ;O.M3;A1. ;I.U1.R.N5.A.C3.A.B.C.E.F.O.O5. ;A1.I;E;S1;U.V;P7;A7;A.C.D.M.N.R.S.E1. ;I4;C.D.N.R.L1;O.O.U.Y.Q1. ;R;S1;W.T9.A1. ;C;D;F;I;L;M;S;V;U7.B.L.M.N.P.R.S.V;W1.R;X1.M;h1.i1.g1.a1.o;p1.i1.o1;n.t2.B;i1.c1.i;T4.a2.i2.g1.a.s1.c;v1.e1.s;e1.a1.m1.p;u1.i2.l;r;à;Um..1.N1..1.C;/1.1;11. .21.1;L1.T;M1.N;N4.C1.L;D2. .P.K;R1. .a;b2;a.i.d;g1.l;i1.g.l2;i.y.m;no. ;a1.n.b;c;d;e1;s.f;g;h;i2.d;n;j;k;l;m;n;o;p;q;r;s;t;u;v;w;p;r3;a.e.u1.k;s3. ;h;t1;r.t4.h;n;r;t;x;z;í;W2.P1.:4.A1.F;I2.B;N1.H.O1.V;R1.F1.C2.N.U.i1.k1.i1.E1.l1.i;X7;a.e.h.i.o.u.y.Y3.e1.t1.h;p;s;[5.A;E;I;a;e;_2._1.i;e;`3.a;e;i;a7; .m1;a1;r1. .n1;d2; .ě.p1;r1;t.r1;t1;í.u1;s1;s1;i1. .v1;u1;t.d3.a1.s1. ;e2.m1. ;r1. ;i2.c1.h1. ;e1.s1.e2.m;r;e8;c1;o1;n1;o1;m1;i1;a.e1;w.l1;i1;t1;e1;i.m1;p1;e1;z.n1;t1;e1;n1;d.s2;a1. .t4;a1; .e1; .i1;m1;a1;r.r1;u1.t.u1.p1. ;w.f3. ;M;y1.i;h9. ;,;.;C;a1.u1.t1;b.e2.i1.r1;a.r1.m1.a1.n;o4.m2.a1; .m;n8; .b.d.e3; .d.y.g.i.k.v.r1.s1. ;u1.r;r1. ;t1;t1;p1;:.i6;b1;n.e1;r.n2;f2;l1;u1;ê.o1;a.s1;t1;a1;l1;a.r1; .s1; .u.k1.u1. ;l3.c1.d;s1. ;v1.a;ma. ;,;R;b1.a.e1.i1.n;f;p;t1.a.u1.l1.t1.i1.c1.a1.m1.p1.i;×;n6. ;V;W;d1; .t;×;o8;c2;h1;o.u1;p.d1;d1;y.f1; .g1;g1;i.no. ;';,;/;a;b;c1.o;d;e2.i;r;f;g;i;l;m;n;o;r;s;t;u;w;y;z;–;r1;i1;g1;e.t1;r1.s;u1;i.r3. ;&;f;s9.,;?;R;f2.e.o.i1.c1.h;l1. ;p2.3;i1. ;r1.g;v3.a.e.i.t2.A;S;uc; ...b2.e;l;f.k2.a;i;m1;a1. .n3;a3; .n5.a;c;n;s;t;r1;y.e2; .i.i8.c2.o1.r1.p;u1.m;d1;i1.o;g1.n;l1.l;m1;o.n;s1.s;v1.o1;c.r5;a.e.i.l.o.s3. ;h;u1.r2;e.p3;a.e.i.t2.m;t;v.w1.a;xb. ;';,;.;8;b;k;l;m1;a.t;y1. ;y1.l;{1.a;|1.a;£1.8;À;Á;Ä;Å;Æ;É;Ò;Ó;Ö;Ü;à;á;æ;è;é1;t3.a;o;u;í;ö;ü1; .Ā;ā;ī;İ;Ō;ō;œ;Ω;α;ε;ω;ϵ;е;–2.e;i;ℓ;";
function fill(node) {
var kidCount = parseInt(dict, 36) || 0,
offset = kidCount && kidCount.toString(36).length;
node.article = dict[offset] == "." ? "a" : "an";
dict = dict.substr(1 + offset);
for (var i = 0; i < kidCount; i++) {
var kid = node[dict[0]] = {}
dict = dict.substr(1);
fill(kid);
}
}
fill(root);
return {
raw: root,
//Usage example: AvsAnSimple.query("example")
//example returns: "an"
query: function (word) {
var node = root, sI = 0, result, c;
do {
c = word[sI++];
} while ('"‘’“”$\''.indexOf(c) >= 0);//also terminates on end-of-string "undefined".
while (1) {
result = node.article || result;
node = node[c];
if (!node) return result;
c = word[sI++] || " ";
}
}
};
})({})
Now, the problem is that I can't find a way to use this function in conjunction with the replaceExpr. The following obviously wouldn't work because of order precedence :
var a = replaceExpr("Theodor is " + AvsAnSimple(zxappearancexz) + "man. He seems rather " + AvsAnSimple(zxpersonalityxz).")
I just recently started learning javascript so my knowledge is rather limited. Any ideas how I could overcome this?
Thank you!
You could use a regular expression to optionally match the " a " or "an" before your word in the input string and store that matched portion in a variable using the String.match() function, then check if that " a " or " an " exists in your matched string, do the manipulations you need to do and store that manipulated string in a separate variable, then use String.replace() to find that previously matched string again, and replace it wit
your manipulated string. The regular expression you could use for this is /(\san?\s)?(zx\w*zx)/gm
See the regular expression here for more context.
Thank you Joseph! With your help I managed to find something that works by using your regular expression. Here's my function :
function replaceExpr(a) {
var nbExprToReplace = 1;
while (nbExprToReplace == 1) {
if (a.search("zx") == -1) {
nbExprToReplace = 0;
} else {
var currentGroup = a.match(/(\san?\s)?(zx\w*xz)/);
var exprToChange = currentGroup[2];
exprToChange = exprToChange.slice(2,-2);
var exprToChange = window[exprToChange];
if (typeof exprToChange !== "function") {
alert("the keyword is not a recognized function!");
break;
} else {
exprToChange = exprToChange();
var final = exprToChange
};
if (currentGroup[1] === undefined) {
} else {
var newArticle = AvsAnSimple.query(exprToChange);
final = newArticle.concat(" " + final)
};
a = a.replace(currentGroup[0], " " + final);
};
};
return a;
};

Variable substitution within a string

I'm trying to come up with some very reusable code that will look up and perform variable substitutions within a string.
The example string below contains a $$ reference to a variable. Format is varname.key.
I want the subText() function to be reusable. The issue I'm having is repvars themselves can require substitution. The code hasn't finished substituting the example text and I'm asking it to substitute the repvars.cr by calling the same function. This seems to through it off. I'm saying that because if I do it separately in works.
var exampleText = "A string of unlimited length with various variable substitutions included $$repvars.cr$$";
var repvars = {
cr: 'Copyright for this is $$repvars.year$$',
year: '2019'
}
function subText(text) {
var subVars = findSubs(text);
return makeSubs(text, subVars);
}
function findSubs(theText) {
var subarr = [];
while (theText.indexOf('$$') > -1) {
theText = theText.substring(theText.indexOf('$$') + 2);
subarr.push(theText.substring(0, theText.indexOf('$$')));
theText = theText.substring(theText.indexOf('$$') + 2);
}
return subarr;
}
function makeSubs(text, subs) {
for (var s = 0; s < subs.length; s++) {
var subst = getSubVal(subs[s]);
text = text.split("$$" + subs[s] + "$$").join(subst);
}
return text;
}
function getSubVal(subvar) {
var subspl = subvar.split('.');
switch (subspl[0]) {
default:
return processRepVar(subspl[1]);
}
}
function processRepVar(rvName) {
var data = getRepVarData(rvName);
if(data.indexOf('$$') > -1) {
subText(data);
} else {
return data;
}
}
function getRepVars() {
return repvars;
}
function getRepVarData(key) {
return getRepVars()[key];
}
subText(exampleText);
Aren't you just missing a return here?
function processRepVar(rvName) {
var data = getRepVarData(rvName);
if(data.indexOf('$$') > -1) {
subText(data);
} else {
return data;
}
}
Changing subText(data) to return subText(data); makes your code work for me.
Working jsfiddle: https://jsfiddle.net/uzxno754/
Have you tried regular expressions for this?
function replace(str, data) {
let re = /\$\$(\w+)\$\$/g;
while (re.test(str))
str = str.replace(re, (_, w) => data[w]);
return str;
}
//
var exampleText = "A string with variables $$cr$$";
var repvars = {
cr: 'Copyright for this is $$year$$',
year: '2019'
}
console.log(replace(exampleText, repvars))
Basically, this repeatedly replaces $$...$$ things in a string until there are no more.

Parse boolean search query back to array

Is there any easy way to parse the following string to array. I can convert array to string but no idea how to convert back to array.
// Input
"Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6"
// Output
[
{
all: ["Keyword1", "Keyword2"],
any: ["Keyword3", "Keyword4"],
not: ["Keyword5", "Keyword6"]
}
]
// Input
"(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)"
// Output
[
{
all: ["Keyword1", "Keyword2"],
any: ["Keyword3", "Keyword4"],
not: ["Keyword5", "Keyword6"]
},
{
all: ["Keyword7", "Keyword8"],
any: ["Keyword9", "Keyword10"],
not: ["Keyword11", "Keyword12"]
}
]
First things first:
I don't validate the input. This answer gives you an approach. You should validate the input, especially since you say it comes from the user :)
We will make use of the matchRecursive function from this blog.
This function will help us group the correct parentheses.
var matchRecursive = function () {
var formatParts = /^([\S\s]+?)\.\.\.([\S\s]+)/,
metaChar = /[-[\]{}()*+?.\\^$|,]/g,
escape = function (str) {
return str.replace(metaChar, "\\$&");
};
return function (str, format) {
var p = formatParts.exec(format);
if (!p) throw new Error("format must include start and end tokens separated by '...'");
if (p[1] == p[2]) throw new Error("start and end format tokens cannot be identical");
var opener = p[1],
closer = p[2],
/* Use an optimized regex when opener and closer are one character each */
iterator = new RegExp(format.length == 5 ? "["+escape(opener+closer)+"]" : escape(opener)+"|"+escape(closer), "g"),
results = [],
openTokens, matchStartIndex, match;
do {
openTokens = 0;
while (match = iterator.exec(str)) {
if (match[0] == opener) {
if (!openTokens)
matchStartIndex = iterator.lastIndex;
openTokens++;
} else if (openTokens) {
openTokens--;
if (!openTokens)
results.push(str.slice(matchStartIndex, match.index));
}
}
} while (openTokens && (iterator.lastIndex = matchStartIndex));
return results;
};
}();
Next, this is the algorithm I would use based on the data you provided:
we determine if we have 1st kind of input or 2nd type, by simply checking if str.startsWith("(");
we initialize the followings:
groupedItems for an array that will transform 2nd type of input into 1st type of input, so that we use the same code for both afterwards
returnArr for the returned data
We loop over the groupedItems and prepare an empty keywordObj
In this loop, we determine which are the any keywords by making use of the matchRecursive function and splitting the result after ' OR ' - the resulting items will be any items
For the rest of the keywords (all or not) we need to get to a single word - so we split again, this time after " ", the result of the split being an array of keywords
We loop over the keywords and determine if they are not keywords by checking if they start with -, otherwise we treat them as all keywords.
Here's the code for it:
function output(str){
var groupedItems = [];
if(str.startsWith("(")){
groupedItems = matchRecursive(str,"(...)");
} else {
groupedItems.push(str);
}
var returnArr = [];
for (var i = 0; i<groupedItems.length;i++){
var keywordObj = {all:[], any:[], not: []};
var thisGroup = groupedItems[i];
var arr = matchRecursive(thisGroup, "(...)");
if (arr.length != 1) throw new Error("unexpected input");
keywordObj.any = arr[0].split(" OR ");
var restOfKeywords = thisGroup.split(" (" + arr[0] + ") ");
for (var j = 0; j<restOfKeywords.length; j++){
var keyWords = restOfKeywords[j].split(" ");
for (var k = 0; k<keyWords.length;k++){
if (keyWords[k].startsWith("-"))
keywordObj.not.push(keyWords[k])
else
keywordObj.all.push(keyWords[k])
}
}
returnArr.push(keywordObj);
}
return returnArr;
}
// input "(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)"
// output [{"all":["Keyword1","Keyword2"],"any":["Keyword3","Keyword4"],"not":["-Keyword5","-Keyword6"]},{"all":["Keyword7","Keyword8"],"any":["Keyword9","Keyword10"],"not":["-Keyword11","-Keyword12"]}]
Here is a solution https://codepen.io/anon/pen/NXMoqo?editors=0012
{
// test cases
// const input = 'Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6';
const input = '(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)';
// const input = '((Keyword1 OR Keyword2 OR Keyword3) Keyword4 Keyword6 -Keyword5 -Keyword7) OR (Keyword8 Keyword9 (Keyword10 OR Keyword11) -Keyword12 Keyword13 -Keyword14 -Keyword15)';
const output = [];
input.split(') OR (').forEach(group => {
let trimmedGroup = group.replace(/^\(/, '').replace(/\)$/, '');
let anyGroup = trimmedGroup.match(/\(.+\)/).join('').replace(/[OR\)\(]/g, '').match(/\w+/g);
let notGroup = trimmedGroup.match(/-\w+/g).map(element => element.replace('-', ''));
let allGroup = trimmedGroup.replace(/\(.+\)/g, '').replace(/-\w+/g, '').match(/\w+/g);
output.push({
all: allGroup,
any: anyGroup,
not: notGroup
});
});
console.log(output);
}
can you check this
var arr = [], obj = {any:[], not:[], all: []};
function splitString(str) {
var object = JSON.parse(JSON.stringify(obj));
var strArr = str.split(" ");
var i=0;
while(strArr.length !== 0 && i<10) {
newStr = strArr.splice(0, 1)[0];
if(newStr.indexOf("(") != -1) {
while(newStr.indexOf(")") == -1) {
object.any.push(newStr.replace(")", "").replace("(", ""))
strArr.splice(0, 1);
newStr = strArr.splice(0, 1)[0];
}
object.any.push(newStr.replace(")", ""))
} else if(newStr.indexOf("-") != -1) {
object.not.push(newStr.substring(1).replace(")", ""))
} else {
object.all.push(newStr.replace(")", ""))
}
i++;
}
arr.push(object)
}
function convertToObj(string){
if(string.indexOf(") OR ") !== -1){
string.split(") OR ").forEach(function(str){
splitString(str.substring(1));
});
} else {
splitString(string);
}
}
convertToObj("Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6")
convertToObj("(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)")
console.log(arr)

Extend Javascript Syntax to Add Typing

I'd like to extend javascript to add custom type checking.
e.g.
function test(welcome:string, num:integer:non-zero) {
console.log(welcome + num)
}
which would compile into:
function test(welcome, num) {
if(Object.prototype.toString.call(welcome) !== "[object String]") {
throw new Error('welcome must be a string')
}
if (!Number.isInteger(num)) {
throw new Error('num must be an integer')
}
console.log(welcome + num)
}
What's the most straightforward way of doing this?
So far i've looked at:
sweet.js (online documentation looks out of date as I think it's going through some sort of internal rewrite)
esprima and escodegen (not sure where to start)
manually parsing using regular expressons
After evaluating all the various options, using sweet.js appears to be the best solution. It's still fairly difficult to get working (and I am probably doing stuff the wrong way) but just in case someone want's to do something similar this here was my solution.
'use strict'
syntax function = function(ctx) {
let funcName = ctx.next().value;
let funcParams = ctx.next().value;
let funcBody = ctx.next().value;
//produce the normal params array
var normalParams = produceNormalParams(funcParams)
//produce the checks
var paramChecks = produceParamChecks(funcParams)
//produce the original funcBody code
//put them together as the final result
var params = ctx.contextify(funcParams)
var paramsArray = []
for (let stx of params) {
paramsArray.push(stx)
}
var inner = #``
var innerStuff = ctx.contextify(funcBody)
for (let item of innerStuff) {
inner = inner.concat(#`${item}`)
}
var result = #`function ${funcName} ${normalParams} {
${paramChecks}
${inner}
}`
return result
function extractParamsAndParamChecks(paramsToken) {
var paramsContext = ctx.contextify(paramsToken)
//extracts the actual parameters
var paramsArray = []
var i = 0;
var firstItembyComma = true
for (let paramItem of paramsContext) {
if (firstItembyComma) {
paramsArray.push({
param: paramItem,
checks: []
})
firstItembyComma = false
}
if (paramItem.value.token.value === ',') {
firstItembyComma = true
i++
} else {
paramsArray[i].checks.push(paramItem.value.token.value)
}
}
for (var i = 0; i < paramsArray.length; i++) {
var checks = paramsArray[i].checks.join('').split(':')
checks.splice(0, 1)
paramsArray[i].checks = checks
}
return paramsArray
}
function produceNormalParams(paramsToken) {
var paramsArray = extractParamsAndParamChecks(paramsToken)
//Produces the final params #string
var inner = #``
var first = true
for (let item of paramsArray) {
if (first === true) {
inner = inner.concat(#`${item.param}`)
} else {
inner = inner.concat(#`,${item.param}`)
}
}
return #`(${inner})`
}
function produceParamChecks(paramsToken) {
var paramsArray = extractParamsAndParamChecks(paramsToken)
var result = #``
for (let paramObject of paramsArray) {
var tests = produceChecks(paramObject)
result = result.concat(#`${tests}`)
}
return result
}
function produceChecks(paramObject) {
var paramToken = paramObject.param
var itemType = paramObject.checks[0]
var checks = paramObject.checks
if (itemType === undefined) return #``
if (itemType === 'array') {
return #`if (Object.prototype.toString.call(${paramToken}) !== "[object Array]") throw new Error('Must be array:' + ${paramToken})`
else {
throw new Error('item type not recognised: ' + itemType)
}
}
}

How can I check a string of words to see if they are an anagram of one word

I am trying to figure out a javascript function that will help resolve this test. I need to be able to determine if the string of words (var matches) that is given is an anagram of the word that I am running through (var subject). In this case there would not be a match. Any and all help will be greatly appreciated. Thank you in advance!
var anagram = require('./anagram');
describe('Anagram', function() {
it("no matches",function() {
var subject = anagram("diaper");
var matches = subject.matches([ "hello", "world", "zombies", "pants"]);
expect(matches).toEqual([]);
});
});
This is what I have so far:
for (var i = 0; i < matches.length; i++) {
if (subject.length != matches[i].length) {
return false
} else if (subject.length == matches[i].length){
var anagram = function(subject, matches) {
return subject.split("").sort("").join("") === matches[i].split("").sort("").join("");
};
}
Here is the fiddle:
http://jsfiddle.net/hn8r4v3u/2/
I alphabetized the letters within the word, as you were doing, in a function.
function getAlphaSortedWord(word) {
var baseWordCharArray = word.split("");
baseWordCharArray.sort();
return baseWordCharArray.join("");
}
The code has a set up:
var baseWord = getAlphaSortedWord("bob");
var thingsToCheck = ["obb", "2", "bob", "", "bo", "ob"];
And then solves it two ways, once with filter and once without it.
var matches = _.filter(thingsToCheck, function (str) {
return (baseWord === getAlphaSortedWord(str));
});
var matches2 = [];
for (index = 0; index < thingsToCheck.length; index++) {
if (baseWord === getAlphaSortedWord(thingsToCheck[index])) {
matches2.push(thingsToCheck[index]);
}
}
You should be able to use these to tie in with your real data for the test to pass.
NOTE, I would add some sanity for "is string" to my function if this is going to be production code.
Found here and it works: https://gist.github.com/AlbertoElias/10005056
function areAnagrams(a, b) {
var c = false;
if (a.length !== b.length) {
return c;
}
var hashMap = {};
var char;
var i;
for (i=0;i<a.length;i++) {
char = a[i];
hashMap[char] = hashMap[char] !== undefined ? hashMap[char]+1 : 1;
}
for (i=0;i<b.length;i++) {
char = b[i];
if (hashMap[char] !== undefined) {
if (hashMap[char] > 1) {
hashMap[char]--;
} else {
delete hashMap[char];
}
} else {
return c;
}
}
if (Object.keys(hashMap).length === 0) c = true;
return c;
}

Categories