Group regex is missing last match - javascript

as given in sample code fstr need match all occurence of regEx_C and need to replace with some dynamic value. and make sure each match should have unique value.
in this sample fstr.match(regEX_C) matches 4 match and i need to replace with 1 dynamic value for each.
var_Viablecells_C = X
var_IVCC_C = Y
var_Viablecells_C = Z
var_IVCC_C = Z1
the value assigned should not match with anyone.
var fstr = '(Math.log(var_Viablecells_C-var_Viablecells_P)/(2-1)+ var_IVCC_C + var_Viablecells_C / var_IVCC_C)';
var regEx_C = /var_(\w+)_C/ig;
var c_val = 5.5;
function putExpValForRegExMatch(fstr, regEx, val) {
var all_match = fstr.match(regEx);
if (null == all_match) return fstr;
console.log(all_match);
for (var i = 0; i < all_match.length; i++) {
console.log(i);
console.log(fstr);
var current_match = regEx.exec(fstr);
if (current_match == null) return fstr;
console.log(current_match);
fstr = replaceRange(fstr, current_match.index, current_match.index + current_match[0].length - 1, '');
fstr = replaceAt(fstr, current_match.index, val);
console.log(fstr);
}
return fstr;
}
function replaceAt(string, index, replace) {
return string.substring(0, index) + replace + string.substring(index + 1);
}
function replaceRange(s, start, end, substitute) {
return s.substring(0, start) + substitute + s.substring(end);
}
console.log(putExpValForRegExMatch(fstr, regEx_C, c_val));

You can just use string.prototype.replace()
var fstr = '(Math.log(var_Viablecells_C-var_Viablecells_P)/(2-1)+ var_IVCC_C + var_Viablecells_C / var_IVCC_C)';
var regEx_C = /var_(\w+)_C/ig;
var c_val = 5.5;
output = fstr.replace(regEx_C,c_val)

Related

Counting Words Between Two Variable Strings

Total newbie + first time poster here with very little experience though I feel this problem is one I could solve with the help of some generous strangers.
I am querying a GDoc and attempting to create a function to count words between two strings for two possible end strings, for example:
Example #1
Definitive Title
*Count these words*
===============
OR
Example #2
Definitive Title
*Count these words*
Other words that are in a table
Definitive Title
*Count these other different words*
===============
In both of the above examples I looking to count the words between a pre-defined string and an end string.
If I ran the function that I am trying to create on Example #1 I am hoping it'd return 3 words. For Example #2 I'd hope that my function returns 8 words.
So far my function looks like this:
function doPost(e) {
var docUrl = e.parameter.docUrl
var text = DocumentApp.openByUrl(docUrl).getBody().getText()
var wordCount = text.split(" ").length
return ContentService.createTextOutput(wordCount.toString()).setMimeType(ContentService.MimeType.TEXT)
}
This returns a word count for the entire document. Any advice to point me in the right direction?
For more dynamic, appropriate and accurate solution, execute the following snippets before the split () function. Regular Expressions often used to provide dynamic solutions. It is a must have skill.
text = text.replace(/(^\s*)|(\s*$)/gi,""); // remove the start and end spaces of the string (like trim ())
text = text.replace(/[ ]{2,}/gi," "); // filter out one or more spaces
text = text.replace(/\n /,"\n"); // filter out news lines with spacing at beginning
wordCount = text.split(" ").length;
Here is a solution to your problem you can log the difference of characters and words or you can log the total amount of words or characters in the two sentaces. You are also going to want to put the bigger sentence on top, otherwise it will give you a negative number.
var x = "count these words";
var y = "count words";
function findCharDif(word1, word2) {
var word1length = word1.length;
var word2length = word2.length;
var difference = word1length - word2length;
var total = word1length + word2length;
console.log(difference);
console.log(total);
}
function findWordDif(sentence1, sentence2) {
var words1 = 0;
var words2 = 0;
for (var i = 0; i < sentence1.length; i++) {
if (sentence1[i] == " ") {
words1++;
} else {
continue
}
}
for (var a = 0; a < sentence2.length; a++) {
if (sentence2[a] == " ") {
words2++;
} else {
continue
}
}
var difference = (words1 + 1) - (words2 + 1); // this logs out the difference of words between the sentences
var totalWords = (words1 + 1) + (words2 + 1); // this logs out the total amount of words
console.log(difference);
console.log(totalWords);
}
findCharDif(x, y);
findWordDif(x, y);
The below code seems to have worked! Was able to sit down with someone and solve it with them:
function doPost(e) {
var docUrl = e.parameter.docUrl
/*
var text = DocumentApp.openByUrl(docUrl).getBody().getText()
var wordCount = text.split(" ").length
*/
var wordCount = countScenario2(docUrl);
return ContentService.createTextOutput(wordCount.toString()).setMimeType(ContentService.MimeType.TEXT)
}
/**
* Count the words from Start Test to a table or ====
*/
function countScenario2(docUrl) {
//var docUrl = 'https://docs.google.com/document/d/';
var doc = DocumentApp.openByUrl(docUrl);
var body = doc.getBody();
var reference = body.findText('Start Text');
var start = getIndex('Start Text', body);
var tables = body.getTables();
var count = 0;
for(var j = 1; j < tables.length ; j ++) {
var end = body.getChildIndex(tables[j]);
for (var i = start + 1; i < end; i++) {
var element = body.getChild(i);
var text = element.getText();
//if(text.length > 0) count += text.split(" ").filter(word => word !== ' ' && word !== '' && word !== ' ').length;
var match = text.match(/\b(\w+)\b/g);
count += (match) ? match.length : 0;
}
console.log(count);
var reference = body.findText('Start Text', reference);
var element = reference.getElement();
var start = body.getChildIndex(element.getParent());
}
var end = getIndex('=========================================================', body);
for (var i = start + 1; i < end; i++) {
var element = body.getChild(i);
var text = element.getText();
//if(text.length > 0) count += text.split(" ").filter(word => word !== ' ' && word !== '' && word !== ' ').length;
var match = text.match(/\b(\w+)\b/g);
count += (match) ? match.length : 0;
}
console.log(count);
return count ;
}
/**
* This will return the index of the element
*
* #param {string} keyword The text to be found
* #param {Body} body This is the body of the document
*/
function getIndex(keyword, body, previous) {
var reference = body.findText(keyword, previous);
var element = reference.getElement();
return body.getChildIndex(element.getParent());
}
/************ */
function testPost(){
var e = {parameter:{docUrl:'https://docs.google.com/document/d/'}};
var result = doPost(e);
console.log(JSON.stringify(result.getContent()));}
/**
* Count the words from Start Text to ====
*/
function countScenario1(docUrl) {
//var docUrl = 'https://docs.google.com/document/d/';
var doc = DocumentApp.openByUrl(docUrl);
var body = doc.getBody();
var start = getIndex('Start Text', body);
var end = getIndex('=========================================================', body);
var count = 0;
for (var i = start + 1; i < end; i++) {
var element = body.getChild(i);
var text = element.getText();
//if(text.length > 0) count += text.split(" ").filter(word => word !== ' ' && word !== '' && word !== ' ').length;
var match = text.match(/\b(\w+)\b/g);
count += (match) ? match.length : 0;
}
console.log(count);
return count;
}
function test(){
var docUrl = 'https://docs.google.com/document/d/';
var wordCount = countScenario2(docUrl);
console.log(wordCount);
}
As what #Rishabh K said in his answer, you should definitely want to replace trailing spaces and multiple spaces to avoid inaccurate results.
However on the other hand, I don't think it answers the OP's question. Correct me if I'm wrong but I think this is what you want:
var sample1 = `This is the start identifier
These words should be included
As well As these ones
Even this
Until it ends
now
Ending identifier
These words shouldn't be included
If any of these appears, the logic is wrong`;
var sample2 = sample1 + `
This is the start identifier
These some few words
should also be included in the result set
Ending identifier`;
var sample3 = sample2 + `
This is the start identifier
Although we have the start identifier above
These words shouldn't be included
because there is no corresponding end identifier`;
function getWordDiffBetween(source, str1, str2) {
// make sure newSource, str1 and str2 are all strings
var args = Array.prototype.slice.call(arguments);
args.forEach(function(str, idx) {
if (typeof str !== 'string') {
throw `Argument ${[idx + 1]} is not a string.`;
}
});
var startId = '<==start==>',
endId = '<==end==>';
var newSource = source.replace(new RegExp(str1, 'g'), startId) // replace the start identifier with our own
.replace(new RegExp(str2 + '|={2,}', 'g'), endId) // replace the end identifier with our own
.replace(/(^\s*)|(\s*$)/gi, "") // remove the start and end spaces of the string (like trim ())
.replace(/\s+/g, ' ') //replace all 1 or more spaces/newline/linefeed with a single space
//separate text into words which are separated by a space since we replaced all newlines with space
var words = newSource.split(' ');
// get the indexes where the start and end identifiers occured
var strOneIdx = getAllIndexes(words, startId, true);
var strTwoIdx = getAllIndexes(words, endId, true);
var results = [], // we will store our results here
i;
for (i = 0; i < strOneIdx.length; i++) {
var idxOne = strOneIdx[i]; // current index for str1
var idxTwo = strTwoIdx.find(x => x > idxOne);
//make sure that idxOne has a partner
if (idxTwo) {
var wordsInBetween = words.slice(idxOne + 1, idxTwo); //get range between idxOne and idxTwo
results = results.concat(wordsInBetween); // add the result
}
}
return results;
}
function getAllIndexes(arr, val) {
var indexes = [],
i;
for (i = 0; i < arr.length; i++) {
if (arr[i] === val) {
indexes.push(i);
}
}
return indexes;
}
var startIdentifier = 'This is the start identifier',
endIdentifier = 'Ending identifier',
wordResults = {
sample1: getWordDiffBetween(sample1, startIdentifier, endIdentifier),
sample2: getWordDiffBetween(sample2, startIdentifier, endIdentifier),
sample3: getWordDiffBetween(sample3, startIdentifier, endIdentifier) //should be equal to sample2
};
console.log(wordResults);
We have 2 functions - getWordDiffBetween and getAllIndexes. For explanation, check the comments I added in noteworthy lines.
Edit (updated snippet above):
It seems like you also want "====================" included as your end identifier. This can be done by changing the code:
.replace(new RegExp(str2, 'g'), endId) // replace the end identifier with our own
into
.replace(new RegExp(str2 + '|={2,}', 'g'), endId) // replace the end identifier with our own
which means match occurence of your <end string> or if there is 2 or more occurences of =. You can also change the number 2 in {2,} to your desired count.

How to increment a string in JavaScript containing leading zeros?

I have string like:
MPG_0023
I want to find something like
MPG_0023 + 1
and I should get
MPG_0024
How to do that in JavaScript? It should take care that if there are no leading zeros, or one leading zero should still work like MPG23 should give MPG24 or MPG023 should give MPG024.
There should be no assumption that there is underscore or leading zeros, the only thing is that first part be any string or even no string and the number part may or may not have leading zeros and it is any kind of number so it should work for 0023 ( return 0024) or for gp031 ( return gp032) etc.
Here's a quick way without using regex.. as long as there's always a single underscore preceding the number and as long as the number is 4 digits, this will work.
var n = 'MPG_0023';
var a = n.split('_');
var r = a[0]+'_'+(("0000"+(++a[1])).substr(-4));
console.log(r);
Or if you do wanna do regex, the underscore won't matter.
var n = "MPG_0099";
var r = n.replace(/(\d+)/, (match)=>("0".repeat(4)+(++match)).substr(-4));
console.log(r);
You can use the regular expressions to make the changes as shown in the following code
var text = "MPG_0023";
var getPart = text.replace ( /[^\d.]/g, '' ); // returns 0023
var num = parseInt(getPart); // returns 23
var newVal = num+1; // returns 24
var reg = new RegExp(num); // create dynamic regexp
var newstring = text.replace ( reg, newVal ); // returns MPG_0024
console.log(num);
console.log(newVal);
console.log(reg);
console.log(newstring);
Using regex along with the function padStart
function add(str, n) {
return str.replace(/(\d+)/, function(match) {
var length = match.length;
var newValue = Number(match) + n;
return newValue.toString(10).padStart(length, "0");
});
}
console.log(add("MPG_023", 101));
console.log(add("MPG_0023", 101));
console.log(add("MPG_0000023", 10001));
console.log(add("MPG_0100023", 10001));
Using regular expression you can do it like this.
var text1 = 'MPG_0023';
var text2 = 'MPG_23';
var regex = /(.*_[0]*)(\d*)/;
var match1 = regex.exec(text1);
var match2 = regex.exec(text2);
var newText1 = match1[1] + (Number(match1[2]) + 1);
var newText2 = match2[1] + (Number(match2[2]) + 1);
console.log(newText1);
console.log(newText2);
Increment and pad the same value (comments inline)
var prefix = "MPG_"
var padDigit = 4; //number of total characters after prefix
var value = "MPG_0023";
console.log("currentValue ", value);
//method for padding
var fnPad = (str, padDigit) => (Array(padDigit + 1).join("0") + str).slice(-padDigit);
//method to get next value
var fnGetNextCounterValue = (value) => {
var num = value.substring(prefix.length); //extract num value
++num; //increment value
return prefix + fnPad(num, padDigit); //prepend prefix after padding
};
console.log( "Next", value = fnGetNextCounterValue(value) );
console.log( "Next", value = fnGetNextCounterValue(value) );
console.log( "Next", value = fnGetNextCounterValue(value) );
One way would e to split the string on the "_" character, increment the number and then add the zeros back to the number.
var testString = "MGP_0023";
var ary = testString.split("_");
var newNumber = Number(ary[1]) + 1;
var result = ary[0] + pad(newNumber);
// helper function to add zeros in front of the number
function pad(number) {
var str = number.toString();
while (str.length < 4) {
str = '0' + str;
}
return str;
}
You could cast to number, increment the value and cast back. Then check if you need leading zeros by looking at the length of the string.
Snippet below:
let str = "MPG_0023",
num = Number(str.substr(4)) + 1,
newStr = String(num);
function addLeading0(str) {
return str.length === 2 ? '00' + str : (str.length === 3 ? '0' + str : str);
}
console.log("MPG_" + addLeading0(newStr));

How can I substitute/replace numbers inside a string as a multiplier for the letter inside the string?

For example: m1 = m , m2 = mm, m3i2 = mmmii
I am trying to find a simple way to do this. Any useful methods?
This is not a homework problem. I am just practicing on my Javascript skills.
So easy with regex and repeat:
function f(str) {
return str.replace(/(.)(\d+)/g, (_, s, n) => s.repeat(n));
}
console.log(f('m1')); // 'm'
console.log(f('m2')); // 'mm'
console.log(f('m3i2')); // 'mmmii'
It can behave a bit inconsistent if the string starts with a digit. You may prefer /(\D?)(\d+)/g.
You could split the string and use the result for returning the string
var s = 'm3i2'.split(/(?=[a-z])/),
result = s.reduce(function (r, a) {
var i = +a.slice(1);
while (i--) {
r += a[0];
}
return r;
}, '');
console.log(result);
here in lambda style
"m2s3".split("").reduce((s,c) => isNaN(c) ? s + c : s + s[s.length-1].repeat(c-1));
mmsss
ES5 Example:
var s = 'm3i2j1';
var re = /([a-z])(\d+)/g;
var matches;
var buffer = [];
while (matches = re.exec(s)) {
buffer.push(Array(+matches[2] + 1).join(matches[1]));
}
var output = buffer.join('');
function replaceNumbers(text) {
var match = text.match(/\D\d*/g), ans = '', i, n;
for (i = 0; i < match.length; ++i) {
n = Number(match[i].substr(1));
ans += match[i].substr(0, 1).repeat(n > 0 ? n : 1);
}
return ans;
}
// Here is the solution I came up with.
function letTheNumberDoTheTalking(str) {
var word = '';
var start = 0;
for (var next = 1; next < str.length; next += 2) {
var letter = str[start];
var multipliedLetter = str[start].repeat(str[next]);
word += multipliedLetter;
start = next + 1;
}
return word;
}
letTheNumberDoTheTalking('m1i1s2i1s2i1p2i1')); //==> 'mississippi'

Take random letters out from a string

I want to remove 3 RANDOM letters from a string.
I can use something like substr() or slice() function but it won't let me take the random letters out.
Here is the demo of what I have right now.
http://jsfiddle.net/euuhyfr4/
Any help would be appreciated!
var str = "hello world";
for(var i = 0; i < 3; i++) {
str = removeRandomLetter(str);
}
alert(str);
function removeRandomLetter(str) {
var pos = Math.floor(Math.random()*str.length);
return str.substring(0, pos)+str.substring(pos+1);
}
If you want to replace 3 random charc with other random chars, you can use 3 times this function:
function substitute(str) {
var pos = Math.floor(Math.random()*str.length);
return str.substring(0, pos) + getRandomLetter() + str.substring(pos+1);
}
function getRandomLetter() {
var letters="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var pos = Math.floor(Math.random()*letters.length);
return letters.charAt(pos);
}
You can split the string to an array, splice random items, and join back to a string:
var arr = str.split('');
for(var i=0; i<3; ++i)
arr.splice(Math.floor(Math.random() * arr.length), 1);
str = arr.join('');
var str = "cat123",
amountLetters = 3,
randomString = "";
for(var i=0; i < amountLetters; i++) {
randomString += str.substr(Math.floor(Math.random()*str.length), 1);
}
alert(randomString);
fiddle:
http://jsfiddle.net/euuhyfr4/7/
This answer states that
It is faster to slice the string twice [...] than using a split followed by a join [...]
Therefore, while Oriol's answer works perfectly fine, I believe a faster implementation would be:
function removeRandom(str, amount)
{
for(var i = 0; i < amount; i++)
{
var max = str.length - 1;
var pos = Math.round(Math.random() * max);
str = str.slice(0, pos) + str.slice(pos + 1);
}
return str;
}
See also this fiddle.
you can shuffle characters in your string then remove first 3 characters
var str = 'congratulations';
String.prototype.removeItems = function (num) {
var a = this.split(""),
n = a.length;
for(var i = n - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
return a.join("").substring(num);
}
alert(str.removeItems(3));
You can use split method without any args.
This would return all chars as a array.
Then you can use any randomiser function as described in Generating random whole numbers in JavaScript in a specific range? , then use that position to get the character at that position.
Have a look # my implementation here
var str = "cat123";
var strArray = str.split("");
function getRandomizer(bottom, top) {
return Math.floor( Math.random() * ( 1 + top - bottom ) ) + bottom;
}
alert("Total length " + strArray.length);
var nrand = getRandomizer(1, strArray.length);
alert("Randon number between range 1 - length of string " + nrand);
alert("Character # random position " + strArray[nrand]);
Code # here https://jsfiddle.net/1ryjedq6/

JavaScript - Need help with string manipulation

say you have:
var foo = "donut [$25]"
What would you need to do in order to delete everything between and including the [ ].
so you get: foo = "donut" after the code is run.
So far I have tried most of the solutions below, but they all either do nothing or crash.
Maybe it's something with my code, please see below:
$('select').change(function () { OnSuccess(mydata); });
function OnSuccess(data) {
var total = 0;
$('select').each(function () {
var sov = parseInt($(this).find('option:selected').attr('value')) || 0; //Selected option value
var sop; //Selected Option Price
for (i = 0; i <= data.length; i++) {
if (data[i].partid == sov) {
sop = data[i].price;
total += sop;
$('#totalprice').html(total);
break;
}
};
//debugger;
$(this).find('option').each(function () {
// $(this).append('<span></span>');
var uov = parseInt($(this).attr('value')) || 0; //Unselected option value
var uop; //Unselected Option Price
for (d = 0; d <= data.length; d++) {
if (data[d].partid == uov) {
uop = data[d].price;
break;
}
}
//debugger;
var newtext = uop - sop;
//{ newtext = "" };
//if (newtext = 0) { newtext.toString; newtext = ""; };
//debugger;
var xtext = $(this).text().toString();
//if (xtext.match(/\[.*\]/) != null) {
xtext.replace(/\s*\[[\s\S]*?\]\s*/g, '').trim();
//}
// var temp = xtext.split('[')[0];
// var temp2 = xtext.split(']')[1];
// resultx = temp + temp2;
if (newtext != 0) {
//xtext.replace(/[.*?]/, "");
$(this).attr("text", xtext + " " + "[" + "$" + newtext + "]");
};
});
});
};
You can also use a regular expression, as Jon Martin pointed out:
var yum = "donut[$25]";
yum.replace(/[.*?]/, ""); // returns "donut"
Alternatively:
var temp = foo.split('[')[0];
var temp2 = foo.split(']')[1];
foo = temp + temp2;
You can use regular expressions (the RegExp() object) to match strings.
var foo = "donut[$25]";
foo.match(/\[.*\]/);
The above will return an array of every item in [square brackets], in this case ["[$25]"].
To just get one result as a string, specify the first index like so:
foo.match(/\[.*\]/)[0];
The above will return "[$25]"
Edit: You know what? I completely misread which bit of the string you're after. This is what you're after:
var foo = "donut[$25]";
foo.match(/\w*/)[0];
How about simply;
var yum = "donut[$25]";
print( yum.substr(0, yum.indexOf("[")) );
>>donut
var begin = foo.search("[");
var end = foo.search("]");
var result = foo.substr(0, begin) + foo.substr(end+1); //Combine anything before [ and after ]
Should be ok right?
Your question leaves unspecified the treatment of the spaces before the [ character, anything after the ], will your string ever contain a linefeed character, multiple occurrences of [..], leading or trailing spaces.
The following will replace all occurrences of 'spaces [ ... ] spaces' with a single space, then it trims the result to remove any leading/trailing spaces.
v.replace (/\s*\[[\s\S]*?\]\s*/g, ' ').trim ();

Categories

Resources