In JavaScript, is it possible to automatically replace a regular expression in a sentence with a randomly generated match of that regular expression? I'm trying to use this approach to automatically paraphrase a sentence using a list of regular expressions, like so:
replaceWithRandomFromRegexes("You aren't a crackpot! You're a prodigy!", ["(genius|prodigy)", "(freak|loony|crackpot|crank|crazy)", "(You're |You are |Thou art )", "(aren't|ain't|are not)"])
Here, each match of each regular expression in the input string should be replaced with a randomly generated match of the regular expression.
function replaceWithRandomFromRegexes(theString, theRegexes){
//For each regex in theRegexes, replace the first match of the regex in the string with a randomly generated match of that regex.
}
This seems to be much simpler than you think. How about:
function randomReplace(subject, groups, wordsOnly) {
var meta = /([.?*+^$[\]\\(){}|-])/g, all = {};
groups.forEach(function(group) {
group.forEach(function(word) { all[word] = group })
});
var r = Object.keys(all).
sort(function(x, y) { return y.length - x.length }).
map(function(x) { return x.replace(meta, "\\$&") }).
join("|");
if(wordsOnly)
r = "\\b(" + r + ")\\b";
return subject.replace(new RegExp(r, "g"), function($0) {
return all[$0][Math.floor(Math.random() * all[$0].length)]
});
}
Example:
s = randomReplace(
"You aren't a crackpot! You're a prodigy!",
[
["genius", "prodigy"],
["freak", "loony", "crackpot", "crank", "crazy"],
["You're ", "You are ", "Thou art "],
["aren't", "ain't", "are not"]
]
);
console.log(s) // You ain't a crank! Thou art a genius!
The expansion function, as discussed in the comments, could be like this:
function expand(s) {
var d = [];
function product(a, b) {
var p = [];
a.map(function(x) { b.map(function(y) { p.push(x + y) })});
return p;
}
function reduce(s) {
var m;
if(s.indexOf("|") >= 0)
return [].concat.apply([], s.split("|").map(reduce));
if(m = s.match(/~(\d+)(.*)/))
return product(reduce(d[m[1]]), reduce(m[2]));
return [s];
}
function add($0, $1) { d.push($1); return '~' + (d.length - 1) }
s = s.replace(/([^()|]+)/g, add);
for(var r = /\(([^()]*)\)/g; s.match(r);)
s = s.replace(r, add);
return reduce(s);
}
Example:
z = "(He|She|It|(B|R)ob(by|)) (real|tru|sure)ly is"
console.log(expand(z))
Result:
[
"He really is",
"He truly is",
"He surely is",
"She really is",
"She truly is",
"She surely is",
"It really is",
"It truly is",
"It surely is",
"Bobby really is",
"Bobby truly is",
"Bobby surely is",
"Bob really is",
"Bob truly is",
"Bob surely is",
"Robby really is",
"Robby truly is",
"Robby surely is",
"Rob really is",
"Rob truly is",
"Rob surely is"
]
Yes, this is certainly possible. I created a function called replaceWithRandomFromRegexes to accomplish this task.
http://jsfiddle.net/KZyZW/2/
for(var i = 0; i < 10; i++){
document.body.innerHTML += (replaceWithRandomFromRegexes("You aren't a crackpot! You're a prodigy!", ["(genius|prodigy)", "(freak|loony|crackpot|crank|crazy)", "(You're |You are |Thou art )", "(aren't|ain't|are not)"]))+"<br/>";
}
function replaceWithRandomFromRegexes(theString, theRegexes) {
//alert(theRegexes);
for (var i = 0; i < theRegexes.length; i++) {
theString = globalReplaceWithRandomFromRegex(theString, theRegexes[i]);
//alert(theRegexes[i]);
}
//alert("All the regexes: " + theRegexes);
return theString;
}
function globalReplaceWithRandomFromRegex(theString, theRegexString) {
var theRegex = new RegExp(theRegexString, "gi");
//replace all matches of theRegex with '<thing to replace>'
theString = theString.replace(theRegex, "<thing to replace>")
//replace the first match of '<thing>'
while (theString.indexOf("<thing to replace>") != -1) {
theString = theString.replace("<thing to replace>", getRandomStringFromNestedParentheses(theRegexString));
}
//alert(theString);
return theString;
}
function getRandomStringFromNestedParentheses(theString) {
while (theString.indexOf("(") != -1) {
theString = replaceInFirstParentheses(theString);
}
return theString;
}
function replaceInFirstParentheses(theString) {
//find the index of the first parentheses
var parenthesesIndex = theString.indexOf("(");
var randomString = getRandomStringInsideParentheses(theString, parenthesesIndex);
//alert(randomString);
//theString = theString.replace();
//find the string to replace
var stringToReplace = theString.substring(parenthesesIndex, getCorrespondingParenthesesIndex(theString, parenthesesIndex) + 1);
//alert(stringToReplace);
theString = theString.replace(stringToReplace, randomString);
//alert(theString);
return theString;
}
function getRandomStringInsideParentheses(string, parenthesesIndex) {
var stringArray = getStringsInsideParentheses(string, parenthesesIndex)
//find out how to pick random in a range
//pick something random from the array declared above
//var theMin = 0;
//var theMax = stringArray.length-1;
var randomNumber = Math.floor(Math.random() * stringArray.length);
return stringArray[randomNumber];
}
function getStringsInsideParentheses(string, parenthesesIndex) {
//alert("calling function getStringsInsideParentheses");
var theString = getStringFromParentheses(string, parenthesesIndex);
for (var i = 0; i < theString.length; i++) {
var theParenthesesNum = getParenthesesNum(theString, i);
if (theString[i] == '|') {
//alert("Parentheses num: " + theParenthesesNum);
if (theParenthesesNum == 0) {
theString = theString.substring(0, i) + "|" + theString.substring(i, theString.length);
i++;
}
}
}
//alert(theString);
return theString.split("||")
}
function getStringFromParentheses(theString, parenthesesIndex) {
return theString.substring(parenthesesIndex + 1, getCorrespondingParenthesesIndex(theString, parenthesesIndex))
}
function getCorrespondingParenthesesIndex(theString, openingParenthesesIndex) {
if (!parenthesesAreMatching(theString)) {
writeMessage("Error: The parentheses do not match!");
return false;
}
if (theString.charAt(openingParenthesesIndex) != "(") {
writeMessage("Error: The index must be an opening parentheses!");
return false;
}
var num = 0;
for (var i = openingParenthesesIndex; i < theString.length; i++) {
if (theString.charAt(i) == "(") {
num++;
}
if (theString.charAt(i) == ")") {
num--;
}
if (num == 0) {
return i;
}
}
writeMessage("Error: The parentheses do not match!");
return false;
}
function parenthesesAreMatching(theString) {
var num = 0;
for (var i = 0; i < theString.length; i++) {
if (theString.charAt(i) == "(") {
num++;
}
if (theString.charAt(i) == ")") {
num--;
}
}
if (num == 0) {
return i;
} else {
return false;
}
}
function getParenthesesNum(theString, index) {
//this should be based on parenthesesAreMatching, but stopping at index
var num = 0;
for (var i = 0; i < index; i++) {
if (theString.charAt(i) == "(") {
num++;
}
if (theString.charAt(i) == ")") {
num--;
}
}
return num;
}
The original sentence was You aren't a crackpot! You're a prodigy! Here are some automatically paraphrased versions of this sentence, as produced by this script:
You are not a freak! Thou art a genius!
You aren't a crackpot! You're a prodigy!
You ain't a crackpot! You are a genius!
You ain't a freak! You're a prodigy!
You are not a crackpot! You are a prodigy!
You are not a loony! You're a prodigy!
You are not a loony! You are a genius!
You are not a loony! You are a prodigy!
You ain't a crackpot! Thou art a prodigy!
You are not a loony! Thou art a prodigy!
Related
im here to ask, if someone can help me with quotation and syntax checking.
im aware of the question solution 1, but i don't fully understand that solution.
here is an example, fully integrated into a website and humbly ask, if anyone can find an error?
function rewriteQuotes(){
var all_p = document.querySelectorAll(`.content_container`);
var regex_s = /[\s\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,\-.\/:;<=>?#\[\]^_`{|}~]/;
for (var i = 0; i < all_p.length; i++) {
if (all_p[i] != null) {
var all_nodes = all_p[i].querySelectorAll("*");
for (var k = 0; k < all_nodes.length; k++) {
if (all_nodes[k].childNodes.length > 0) {
var all_children = all_nodes[k].childNodes;
for (var t = 0; t < all_children.length; t++) {
if (all_children[t].nodeName == "#text") {
all_children[t].textContent = all_children[t].textContent.replace(/"/g,"\“");
all_children[t].textContent = all_children[t].textContent.replace(/\s\“/g,"\ „");
if (all_children[t].textContent.charAt(0)== "\“") {
if (all_children[t].textContent.charAt(1) === "") {
} else {
var char_1 = all_children[t].textContent.charAt(1);
if (regex_s.test(char_1)) {
} else {
all_children[t].textContent = "\„" + all_children[t].textContent.substring(1);
}
}
}
}
}
}
}
}
}
};
document.addEventListener('DOMContentLoaded',function(){
setTimeout(function(){
rewriteQuotes();
},1);
});
<div class="content_container">
<h2>"Hello"</h2>
<p>my "aunti" was driving over the "cat" with her "<em>skateboard</em>".</p>
</div>
You can simplify your regex and capture groups of "..." and then replace the quotes of those groups with your desired ones:
const regex = /"(.*?)"/g;
const str = `my "aunti" was driving over the "cat" with her "car"`;
const subst = `„$1“`;
const result = str.replace(regex, subst);
console.log('Original: ', str);
console.log('Result: ', result);
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;
};
I have a function like this that's provided by a user:
function replace_function(string) {
return string.replace(/:smile:/g, '⻇')
.replace(/(foo|bar|baz)/g, 'text_$1');
}
and I have input string like this:
var input = 'foo bar :smile: xxxx';
and I have a number from 0 to length of the input string that I use to do substring to split the string.
I need to find number (position) that will match output string after replacement so the split is in the same visual place. The split is just for visualization I only need the number.
The output string can have the same length, this is only for the case when length of input and output is different (like width provided function and input string)
function replace_function(string) {
return string.replace(/:smile:/g, '⻇')
.replace(/(foo|bar|baz)/g, 'text_$1');
}
var textarea = document.querySelector('textarea');
var pre = document.querySelector('pre');
function split() {
var input = textarea.value;
var output = replace_function(input);
// find position for output
var position = textarea.selectionStart;
var split = [
output.substring(0, position),
output.substring(position)
];
pre.innerHTML = JSON.stringify(split);
}
textarea.addEventListener('click', split);
<textarea>xxx foo xxx bar xxx :smile: xxxx</textarea>
<pre></pre>
when you click in the middle of the word that get replaced the position/split need to be after the output word. If you click before, between or after the word the position need to be in the same place (the position in each case will be different to match the correct place)
UPDATE: here is my code that work for :smile: only input, but there is need to be text before :smile: (input = ":smile: asdas" and position in the middle of smile and the position is off)
it work for foo replaced by text_foo but not in the case when there is :smile: before foo (input "asd :smile: asd foo").
var get_position = (function() {
function common_string(formatted, normal) {
function longer(str) {
return found && length(str) > length(found) || !found;
}
var formatted_len = length(formatted);
var normal_len = length(normal);
var found;
for (var i = normal_len; i > 0; i--) {
var test_normal = normal.substring(0, i);
var formatted_normal = replace_function(test_normal);
for (var j = formatted_len; j > 0; j--) {
var test_formatted = formatted.substring(0, j);
if (test_formatted === formatted_normal &&
longer(test_normal)) {
found = test_normal;
}
}
}
return found || '';
}
function index_after_formatting(position, command) {
var start = position === 0 ? 0 : position - 1;
var command_len = length(command);
for (var i = start; i < command_len; ++i) {
var substr = command.substring(0, i);
var next_substr = command.substring(0, i + 1);
var formatted_substr = replace_function(substr);
var formatted_next = replace_function(next_substr);
var substr_len = length(formatted_substr);
var next_len = length(formatted_next);
var test_diff = Math.abs(next_len - substr_len);
if (test_diff > 1) {
console.log('return ' + i);
return i;
}
}
}
return function get_formatted_position(position, command) {
var formatted_position = position;
var string = replace_function(command);
var len = length(string);
var command_len = length(command);
if (len !== command_len) {
var orig_sub = command.substring(0, position);
var orig_len = length(orig_sub);
var sub = replace_function(orig_sub);
var sub_len = length(sub);
var diff = Math.abs(orig_len - sub_len);
if (false && orig_len > sub_len) {
formatted_position -= diff;
} else if (false && orig_len < sub_len) {
formatted_position += diff;
} else {
var index = index_after_formatting(position, command);
var to_end = command.substring(0, index + 1);
//formatted_position -= length(to_end) - orig_len;
formatted_position -= orig_len - sub_len;
if (orig_sub && orig_sub !== to_end) {
var formatted_to_end = replace_function(to_end);
var common = common_string(formatted_to_end, orig_sub);
var re = new RegExp('^' + common);
var before_end = orig_sub.replace(re, '');
var to_end_rest = to_end.replace(re, '');
var to_end_rest_len = length(replace_function(to_end_rest));
if (before_end && orig_sub !== before_end) {
var commnon_len = length(replace_function(common));
formatted_position = position - length(before_end) + to_end_rest_len;
}
}
}
if (formatted_position > len) {
formatted_position = len;
} else if (formatted_position < 0) {
formatted_position = 0;
}
}
return formatted_position;
};
})();
function length(str) {
return str.length;
}
function replace_function(string) {
return string.replace(/:smile:/g, '⻇')
.replace(/(foo|bar|baz)/g, 'text_$1');
}
var textarea = document.querySelector('textarea');
var pre = document.querySelector('pre');
function split() {
var input = textarea.value;
var output = replace_function(input);
// find position for output
var position = get_position(textarea.selectionStart, input);
var split = [
output.substring(0, position),
output.substring(position)
];
pre.innerHTML = JSON.stringify(split);
}
textarea.addEventListener('click', split);
<textarea>xxxx :smile: xxxx :smile: xxx :smile:</textarea>
<pre></pre>
To do this, you'll have to do the replace operation yourself with a RegExp#exec loop, and keep track of how the replacements affect the position, something along these lines (but this can probably be optimized):
function trackingReplace(rex, string, replacement, position) {
var newString = "";
var match;
var index = 0;
var repString;
var newPosition = position;
var start;
rex.lastIndex = 0; // Just to be sure
while (match = rex.exec(string)) {
// Add any of the original string we just skipped
if (rex.global) {
start = rex.lastIndex - match[0].length;
} else {
start = match.index;
rex.lastIndex = start + match[0].length;
}
if (index < start) {
newString += string.substring(index, start);
}
index = rex.lastIndex;
// Build the replacement string. This just handles $$ and $n,
// you may want to add handling for $`, $', and $&.
repString = replacement.replace(/\$(\$|\d)/g, function(m, c0) {
if (c0 == "$") return "$";
return match[c0];
});
// Add on the replacement
newString += repString;
// If the position is affected...
if (start < position) {
// ... update it:
if (rex.lastIndex < position) {
// It's after the replacement, move it
newPosition = Math.max(0, newPosition + repString.length - match[0].length);
} else {
// It's *in* the replacement, put it just after
newPosition += repString.length - (position - start);
}
}
// If the regular expression doesn't have the g flag, break here so
// we do just one replacement (and so we don't have an endless loop!)
if (!rex.global) {
break;
}
}
// Add on any trailing text in the string
if (index < string.length) {
newString += string.substring(index);
}
// Return the string and the updated position
return [newString, newPosition];
}
Here's a snippet showing us testing that with various positions:
function trackingReplace(rex, string, replacement, position) {
var newString = "";
var match;
var index = 0;
var repString;
var newPosition = position;
var start;
rex.lastIndex = 0; // Just to be sure
while (match = rex.exec(string)) {
// Add any of the original string we just skipped
if (rex.global) {
start = rex.lastIndex - match[0].length;
} else {
start = match.index;
rex.lastIndex = start + match[0].length;
}
if (index < start) {
newString += string.substring(index, start);
}
index = rex.lastIndex;
// Build the replacement string. This just handles $$ and $n,
// you may want to add handling for $`, $', and $&.
repString = replacement.replace(/\$(\$|\d)/g, function(m, c0) {
if (c0 == "$") return "$";
return match[c0];
});
// Add on the replacement
newString += repString;
// If the position is affected...
if (start < position) {
// ... update it:
if (rex.lastIndex < position) {
// It's after the replacement, move it
newPosition = Math.max(0, newPosition + repString.length - match[0].length);
} else {
// It's *in* the replacement, put it just after
newPosition += repString.length - (position - start);
}
}
// If the regular expression doesn't have the g flag, break here so
// we do just one replacement (and so we don't have an endless loop!)
if (!rex.global) {
break;
}
}
// Add on any trailing text in the string
if (index < string.length) {
newString += string.substring(index);
}
// Return the string and the updated position
return [newString, newPosition];
}
function show(str, pos) {
console.log(str.substring(0, pos) + "|" + str.substring(pos));
}
function test(rex, str, replacement, pos) {
show(str, pos);
var result = trackingReplace(rex, str, replacement, pos);
show(result[0], result[1]);
}
for (var n = 3; n < 22; ++n) {
if (n > 3) {
console.log("----");
}
test(/([f])([o])o/g, "test foo result foo x", "...$2...", n);
}
.as-console-wrapper {
max-height: 100% !important;
}
And here's your snippet updated to use it:
function trackingReplace(rex, string, replacement, position) {
var newString = "";
var match;
var index = 0;
var repString;
var newPosition = position;
var start;
rex.lastIndex = 0; // Just to be sure
while (match = rex.exec(string)) {
// Add any of the original string we just skipped
if (rex.global) {
start = rex.lastIndex - match[0].length;
} else {
start = match.index;
rex.lastIndex = start + match[0].length;
}
if (index < start) {
newString += string.substring(index, start);
}
index = rex.lastIndex;
// Build the replacement string. This just handles $$ and $n,
// you may want to add handling for $`, $', and $&.
repString = replacement.replace(/\$(\$|\d)/g, function(m, c0) {
if (c0 == "$") return "$";
return match[c0];
});
// Add on the replacement
newString += repString;
// If the position is affected...
if (start < position) {
// ... update it:
if (rex.lastIndex < position) {
// It's after the replacement, move it
newPosition = Math.max(0, newPosition + repString.length - match[0].length);
} else {
// It's *in* the replacement, put it just after
newPosition += repString.length - (position - start);
}
}
// If the regular expression doesn't have the g flag, break here so
// we do just one replacement (and so we don't have an endless loop!)
if (!rex.global) {
break;
}
}
// Add on any trailing text in the string
if (index < string.length) {
newString += string.substring(index);
}
// Return the string and the updated position
return [newString, newPosition];
}
function replace_function(string, position) {
var result = trackingReplace(/:smile:/g, string, '⻇', position);
result = trackingReplace(/(foo|bar|baz)/g, result[0], 'text_$1', result[1]);
return result;
}
var textarea = document.querySelector('textarea');
var pre = document.querySelector('pre');
function split() {
var position = textarea.selectionStart;
var result = replace_function(textarea.value, position);
var string = result[0];
position = result[1];
var split = [
string.substring(0, position),
string.substring(position)
];
pre.innerHTML = JSON.stringify(split);
}
textarea.addEventListener('click', split);
<textarea>:smile: foo</textarea>
<pre></pre>
First of all sorry for bothering with a question asked several times before.But I have to say that I did read through the related questions about string permutations and I could not figure out the actual problem with the code I have below. I want to return the combinations of a string.Please help me out in finding the mistake ! PS: I have just started learning javascript!
var result = [];
function doPerm(prefix, suffix, result) {
if (suffix.length === 0)
result.push(prefix);
else {
for (i = 0; i < suffix.length; i++) {
doPerm(prefix + suffix.charAt(i), suffix.slice(0, i) + suffix.slice(i + 1), result);
}
}
}
function permAlone(str) {
var prefix = "";
var suffix = str;
doPerm(prefix, suffix, result);
return result;
}
console.log(permAlone('aab'));
INPUT:'aab'
OUTPUT:[aab,aab,aba,aba,baa,baa]
Your logic was correct actually, you just declared i without var in for loop which made it global and was giving you errors. It seems to be working once that is corrected:
var result = [];
function doPerm(prefix, suffix, result) {
if (suffix.length === 0)
result.push(prefix);
else {
for (var i = 0; i < suffix.length; i++) {
doPerm(prefix + suffix.charAt(i), suffix.slice(0, i) + suffix.slice(i + 1), result);
}
}
}
function permAlone(str) {
var prefix = "";
var suffix = str;
doPerm(prefix, suffix, result);
return result;
}
console.log(permAlone('aab'));
This is a bit of on the back of a piece of paper thinking but.
for(i;i<string.length;i++) {
var s = string.slice(i,i+1);
var c = string.charAt(i);
var q = s.split("");
for(b=0;b<q.length;b++) {
var newArray = q.slice();
newArray.splice(b,0,c);
result.push(newArray.join());
}
}
does that work?
UPDATE this seems to work!
<script>
var string = "aab";
var result = [];
for(i=0;i<string.length;i++) {
var c = string.charAt(i);
var q = string.split("");
q.splice(i,1);
console.log("first");
console.log(q);
console.log(c);
for(b=0;b<q.length;b++) {
var newArray = q.slice();
newArray.splice(b,0,c);
result.push(newArray.join());
}
}
console.log(result);
</script>
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;
}