Calculation within Regular Expression - javascript

I had a crazy idea.
I want to do a calculation within a regular expression but I'm not sure if it's possible. Basically I have a line that says:
Category:
And every time you click a button it will say:
Category:
Category 1:
Category 2:
etc. I am doing a string of functions on a jQuery selector right now as such:
var newHTML = selector.closest('.row').clone().html().replace(/(Category)(\s)(\d)/g,'$1$2' + (parseInt('$3') + 1)).replace('Category:','Category 2:');
So it does the first replace and if it's the original 'Category' it won't match and will run the second replace. If it does match, I want it to increment the number on the end of the expression by one. I thought maybe I could parseInt() the variable and add one but that doesn't work since parseInt('$3') appears to return NaN and doesn't recognize the variable as an integer.
I know there are plenty of other ways to do this but I just stumbled across it, stumped myself and always like to find any answer to a good question...
Any thoughts? Thanks!

Like in many other languages, JavaScript evaluates the arguments before they are passed to the function. So in your case '$1$2' + (parseInt('$3') + 1)) is evaluated first, which results in the string '$1$2NaN', and that is passed to .replace. parseInt('$3') is NaN because the string '$3' cannot be converted to a number:
> parseInt('$3')
NaN
If you want to perform any computation with the matches, you have to pass a function as second argument:
.replace(/(Category)(\s)(\d)/g, function(match, $1, $2, $3) {
return $1 + $2 + (parseInt($3) + 1));
})
(of course you can name the arguments whatever you want)
You can learn more about passing callbacks to .replace in the MDN documentation.

Further to #FelixKling's answer here is a working demo, just to show what adjustment you might have make.
$('.cat').on('click', function() {
$(this).html(function(i,html) {
return html.replace(/(Category)(\s?)(\d*)/g, function(match, x, y, z) {
y = y || ' ';
z = z || 0;
return x + y + (+z + 1);
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="cat">Category</div>
<div class="cat">Goint with Category Blah Blah Blah</div>

Related

Look for substring in a string with at most one different character-javascript

I am new in programing and right now I am working on one program. Program need to find the substring in a string and return the index where the chain starts to be the same. I know that for that I can use "indexOf". Is not so easy. I want to find out substrings with at moste one different char.
I was thinking about regular expresion... but not really know how to use it because I need to use regular expresion for every element of the string. Here some code wich propably will clarify what I want to do:
var A= "abbab";
var B= "ba";
var tb=[];
console.log(A.indexOf(B));
for (var i=0;i<B.length; i++){
var D=B.replace(B[i],"[a-z]");
tb.push(A.indexOf(D));
}
console.log(tb);
I know that the substring B and string A are the lowercase letters. Will be nice to get any advice how to make it using regular expresions. Thx
Simple Input:
A B
1) abbab ba
2) hello world
3) banana nan
Expected Output:
1) 1 2
2) No Match!
3) 0 2
While probably theoretically possible, I think it would very complicated to try this kind of search while attempting to incorporate all possible search query options in one long complex regular expression. I think a better approach is to use JavaScript to dynamically create various simpler options and then search with each separately.
The following code sequentially replaces each character in the initial query string with a regular expression wild card (i.e. a period, '.') and then searches the target string with that. For example, if the initial query string is 'nan', it will search with '.an', 'n.n' and 'na.'. It will only add the position of the hit to the list of hits if that position has not already been hit on a previous search. i.e. It ensures that the list of hits contains only unique values, even if multiple query variations found a hit at the same location. (This could be implemented even better with ES6 sets, but I couldn't get the Stack Overflow code snippet tool to cooperate with me while trying to use a set, even with the Babel option checked.) Finally, it sorts the hits in ascending order.
Update: The search algorithm has been updated/corrected. Originally, some hits were missed because the exec search for any query variation would only iterate as per the JavaScript default, i.e. after finding a match, it would start the next search at the next character after the end of the previous match, e.g. it would find 'aa' in 'aaaa' at positions 0 and 2. Now it starts the next search at the next character after the start of the previous match, e.g. it now finds 'aa' in 'aaaa' at positions 0, 1 and 2.
const findAllowingOneMismatch = (target, query) => {
const numLetters = query.length;
const queryVariations = [];
for (let variationNum = 0; variationNum < numLetters; variationNum += 1) {
queryVariations.push(query.slice(0, variationNum) + "." + query.slice(variationNum + 1));
};
let hits = [];
queryVariations.forEach(queryVariation => {
const re = new RegExp(queryVariation, "g");
let myArray;
while ((searchResult = re.exec(target)) !== null) {
re.lastIndex = searchResult.index + 1;
const hit = searchResult.index;
// console.log('found a hit with ' + queryVariation + ' at position ' + hit);
if (hits.indexOf(hit) === -1) {
hits.push(searchResult.index);
}
}
});
hits = hits.sort((a,b)=>(a-b));
console.log('Found "' + query + '" in "' + target + '" at positions:', JSON.stringify(hits));
};
[
['abbab', 'ba'],
['hello', 'world'],
['banana', 'nan'],
['abcde abcxe abxxe xbcde', 'abcd'],
['--xx-xxx--x----x-x-xxx--x--x-x-xx-', '----']
].forEach(pair => {findAllowingOneMismatch(pair[0], pair[1])});

regex for nested parenthesis

Using javascript, im trying to make a node.js module to parse predicate logic statements.
I've been working on this regex for a bit and I just can't get it to behave the way i want
1. /\(((?:[^{}]*\([^{}]*\))*[^{}]*?)\)/
2. .replace(/\)((?:[^{}]*\)[^{}]*\))*[^{}]*?)\(/,'):::(')
the latter works fine on things like (a&s&d&a&s&d)->(a&s&(d)&s|(d)) but i just switched the delimiters...
what I'm trying to do is change a statement like
((r|a)&(s|r))&(~r)->(r|(q&r))->q
into
1->2->q
I can certainly write a procedural function to do it, that would be a fine solution. But Im really stuck on this.
The only real specification is the regex needs to respect the outermost parenthesis the most, and be able to replace separate ones.
Because this is not regex friendly I put togethor a couple of functions that do what you are looking for. The first matches parenthesis with depth:
function match_parens(code_to_test, level, opening, closing){
var sub_match, matched;
return code_to_test.replace(new RegExp('^([^'+opening+closing+']*(.))[\\s\\S]*$'), function(full_match, matched, $2, offset, original){
if ($2 == opening){
sub_match = match_parens(original.substr(offset+matched.length), level + 1, opening, closing);
matched = matched + sub_match
}
else if (level > 1){
sub_match = match_parens(original.substr(offset+matched.length), level - 1, opening, closing);
matched += sub_match;
}
return matched;
});
}
This function takes a string and returns everything up until the closing element.
The next function helps pulls a string passed to it apart, replacing all content in parenthesis with escalating numbers:
function pull_apart(testString){
var count = 1,
returnString = '',
tempIndex = testString.indexOf('(');
while (tempIndex !== -1){
returnString += testString.substring(0,tempIndex)+count;
count += 1;
testString = testString.substring(testString.indexOf('(') + match_parens(testString.substr(tempIndex + 1), 1, '(', ')').length+1)
tempIndex = testString.indexOf('(');
}
returnString += testString;
return returnString;
}
Running pull_apart('((r|a)&(s|r))&(~r)->(r|(q&r))->q') returns "1&2->3->q", which is what you are looking for. While this is not entirely regex, it is utilized in the paren matching function up above. I'm not sure if this fits whatever use case you had in mind, but hopefully it helps.

Eval alternative

This code works as a calculator, but the scratch pad at codeacademy tells me that eval is evil. Is there another way to do the same thing without using eval?
var calculate = prompt("Enter problem");
alert(eval(calculate));
eval evaluates the string input as JavaScript and coincidentally JavaScript supports calculations and understands 1+1, which makes it suitable as a calculator.
If you don't want to use eval, which is good, you have to parse that string yourself and, finally, do the computation yourself (not exactly yourself though). Have a look at this math processor, which does what you want.
Basically what you do is:
Read the input string char by char (with this kind of problem it's still possible)
Building a tree of actions you want to do
At the end of the string, you evaluate the tree and do some calculations
For example you have "1+2/3", this could evaluate to the following data structure:
"+"
/ \
"1" "/"
/ \
"2" "3"
You could then traverse that structure from top to bottom and do the computations.
At first you've got the "+", which has a 1 on the left side and some expression on the right side,
so you have to evaluate that expression first. So you go to the "/" node, which has two numeric children. Knowing that, you can now compute 2/3 and replace the whole "/" node with the result of that. Now you can go up again and compute the result of the "+" node: 1 + 0.66. Now you replace that node with the result and all you've got left is the result of the expression.
Some pseudo code on how this might look in your code:
calculation(operator, leftValue, rightValue):
switch operator {
case '+': return leftValue + rightValue
case '-': return 42
}
action(node):
node.value = calculation(node.operator, action(node.left) action(node.right))
As you might have noticed, the tree is designed in such a way that it honors operator precedence. The / has a lower level than the +, which means it get's evaluated first.
However you do this in detail, that's basically the way to go.
You can use the expression parser that is included in the math.js library:
http://mathjs.org
Example usage:
mathjs.evaluate('1.2 / (2.3 + 0.7)'); // 0.4
mathjs.evaluate('5.08 cm in inch'); // 2 inch
mathjs.evaluate('sin(45 deg) ^ 2'); // 0.5
mathjs.evaluate('9 / 3 + 2i'); // 3 + 2i
mathjs.evaluate('det([-1, 2; 3, 1])'); // -7
You can use eval safely for a simple arithmetic calculator by filtering the input- if you only accept digits, decimal points and operators (+,-,*,/) you won't get in much trouble. If you want advanced Math functions, you are better off with the parser suggestions.
function calculate(){
"use strict";
var s= prompt('Enter problem');
if(/[^0-9()*+\/ .-]+/.test(s)) throw Error('bad input...');
try{
var ans= eval(s);
}
catch(er){
alert(er.message);
}
alert(ans);
}
calculate()
I write some functions when I had a problem like this. Maybe this can help:
data = [
{id:1,val1:"test",val2:"test2",val2:"test3"},
{id:2,val1:"test",val2:"test2",val2:"test3"},
{id:3,val1:"test",val2:"test2",val2:"test3"}
];
datakey = Object.keys(data[0]);
// here's a fix for e['datakey[f]'] >> e[x]
vix = function(e,f){
a = "string";
e[a] = datakey[f];
x = e.string;
end = e[x];
delete e.string;
return end;
};
// here's a fix to define that variable
vox = function(e,f,string){
a = "string";
e[a] = datakey[f];
x = e.string;
end = e[x] = string;
delete e.string;
};
row = 2 // 3th row ==> {id:3,val1:"test",val2:"test2",val2:"test3"}
column = 1 //datakey 2 ==> val1
vox(data[row],column,"new value");
alert(data[2].val1); //the value that we have changed

variable array + regular expression not working together?

im making a small smiley script , what it does is to change ::1:: into an image html for a div.
the code as follow:
var smileys = {
'1': 'http://domain.com/smiley1.gif',
'2': 'http://domain.com/smiley2.gif',
'3': 'http://domain.com/smiley3.gif'
};
function checksmileys(){
x$('.message').each(function()
var start = '<img src="';
var end = '">';
x$(this).html( x$(this).html().replace(/::(\d+)::/g, start + smileys['$1'] + end) );
});
Checksmileys function is triggered by user event.
However it is not able to get the digit(which is the id) out of a sentence.
It kept on producing this <img src="undefined">
My HTML example as follows:
<div id="chat">
<ul>
<li class="message">Hi john</li>
<li class="message">what are you doing</li>
<li class="message">::1:: nothing</li>
<li class="message">hi</li>
<li class="message">nice to meet you ::1::</li>
</ul>
</div>
Where is my problem here?
I guess you need a function here:
html = html.replace(/::(\d+)::/g, function($0, $1) { return start + smileys[$1] + end })
here's when the functional form of html() comes in handy
$(this).html(function(_, oldhtml) {
return oldhtml.replace(/::(\d+)::/g, function($0, $1) {
return start + smileys[$1] + end;
})
})
In JavaScript, property names don't have prefixes like they often do in PHP. The name of the property you create in your smileys object is 1, not $1, so change smileys['$1'] to smileys['1'].
Update: From your comment below, it seems you're trying to use $1 to refer to the capture group. That only works when $1 is part of the string you pass in, but the expression start + smileys['$1'] + end is evaluated before the call to replace and then passed into it. smileys['$1'] will be undefined.
Since you're trying to do a lookup, your best bet is to pass in a function that does the lookup:
x$(this).html( x$(this).html().replace(/::(\d+)::/g, function(m, c1) {
return start + smileys[c1] + end;
}) );
c1 is the text of the first capture group. More
You've called it an array, which I'm guessing is because you're used to the term "associative array" from PHP. Your smileys object is just an object, not an array. In JavaScript, when we say "array", we mean something created via [] or new Array, which has specific handling for a certain class of property names (numeric ones), a special length property, and some handy array-like functions. What you've done with smileys is perfectly fine and completely normal, we just tend not to use the word "array" for it ("map" is more common in the JS world).

javascript parseFloat '500,000' returns 500 when I need 500000

How would it be a nice way of handling this?
I already thought on removing the comma and then parsing to float.
Do you know a better/cleaner way?
Thanks
parseFloat( theString.replace(/,/g,'') );
I don't know why no one has suggested this expression-
parseFloat( theString.replace(/[^\d\.]/g,'') );
Removes any non-numeric characters except for periods. You don't need custom functions/loops for this either, that's just overkill.
Nope. Remove the comma.
You can use the string replace method, but not in a one liner as a regexp allows.
while(str.indexOf(',')!=-1)str= str.replace(',','');
parseFloat(str);
Or to make a single expression without a regexp=
return parseFloat(str.split(',').join(''));
I'd use the regexp.
I don't have enough reputation to add a comment, but for anyone wondering on the performance for regex vs split/join, here's a quick fiddle: https://jsfiddle.net/uh3mmgru/
var test = "1,123,214.19";
var t0 = performance.now();
for (var i = 0; i < 1000000; i++)
{
var a = parseFloat(test.replace(/,/g,''));
}
var t1 = performance.now();
document.write('Regex took: ' + (t1 - t0) + ' ms');
document.write('<br>')
var t0 = performance.now();
for (var i = 0; i < 1000000; i++)
{
var b = parseFloat(test.split(',').join(''));
}
var t1 = performance.now();
document.write('Split/join took: ' + (t1 - t0) + ' ms');
The results I get are (for 1 million loops each):
Regex: 263.335 ms
Split/join: 1035.875 ms
So I think its safe to say that regex is the way to go in this scenario
Building on the idea from #kennebec, if you want to make sure that the commas are correct, and you don't want to replace commas, you could try something like this:
function myParse(num) {
var n2 = num.split(",")
out = 0
for(var i = 0; i < n2.length; i++) {
out *= 1000;
out += parseFloat(n2[i])
}
return out
}
alert(myParse("1,432,85"));
// Returns 1432085, as the comma is misplaced.
It may not be as fast, but you wanted alternatives :)
What about a simple function to solve most of the common problems?
function getValue(obj) {
Value = parseFloat( $(obj).val().replace(/,/g,'') ).toFixed(2);
return +Value;
}
The above function gets values from fields (using jQuery) assuming the entered values are numeric (I rather validate fields while user is entering data, so I know for sure field content is numeric).
In case of floating point values, if well formatted in the field, the function will return a float point value correctly.
This function is far from complete, but it quickly fix the "," (comma) issue for values entered as 1,234.56 or 1,234,567. It will return valid number as far the content is numeric.
The + (plus) sign in front of the variable Value in the return command is a "dirty trick" used in JavaScript to assure the variable content returned will be numeric.
it is easy to modify the function to other purposes, such as (for instance), convert strings to numeric values taking care of the "," (comma) issue:
function parseValue(str) {
Value = parseFloat( str.replace(/,/g,'') ).toFixed(2);
return +Value;
}
Both operations can even be combined in one function. I.e.:
function parseNumber(item,isField=false) {
Value = (isField) ? parseFloat( $(item).val().replace(/,/g,'') ).toFixed(2) : parseFloat( item.replace(/,/g,'') ).toFixed(2)
return +Value;
}
In such case, if function is called result = parseNumber('12,092.98'); it will parse the value as it is a String. But if called as result = parseNumber('#MyField', true); it will try to obtain the value from '#MyField'.
As I said before, such functions are far from complete, and can be expanded in many ways. One idea is to check the first character of the given parameter (string) and decide based on the string format where to obtain the value to be parsed (if 1st character is = '#' then it is an ID from a DOM object, otherwise, if it begins with a number, it must be a string to be parsed).
Try it... Happy coding.

Categories

Resources