I make a serialized list (with JQuery) and then want to delete a Parameter/Value pair from the list. What's the best way to do this? My code seems kinda clunky to take care of edge conditions that the Parameter/Value pair might be first, last, or in the middle of the list.
function serializeDeleteItem(strSerialize, strParamName)
{
// Delete Parameter/Value pair from Serialized list
var strRegEx;
var rExp;
strRegEx = "((^[?&]?" + strParamName + "\=[^\&]*[&]?))|([&]" + strParamName + "\=[^\&]*)|(" + strParamName + "\=[^\&]*[&])";
rExp = new RegExp(strRegEx, "i");
strSerialize = strSerialize.replace(rExp, "");
return strSerialize;
}
Examples / Test rig at http://jsfiddle.net/7Awzw/
EDIT: Modified the test rig to preserve any leading "?" or "&" so that function could be used with URL Query String or fragment of serialized string
See: http://jsfiddle.net/7Awzw/5/
This version is longer than yours, but imho it's more maintainable. It will find and remove the serialized parameter regardless of where it is in the list.
Notes:
To avoid problems with removing items in the middle of an array, we iterate in reverse.
For exact matching of parameter names, we expect them to start at the beginning of the split string, and to terminate with =.
Assuming there is just one instance of the given param, we break once it's found. If there may be more, just remove that line.
Code
function serializeDeleteItem(strSerialize, strParamName)
{
var arrSerialize = strSerialize.split("&");
var i = arrSerialize.length;
while (i--) {
if (arrSerialize[i].indexOf(strParamName+"=") == 0) {
arrSerialize.splice(i,1);
break; // Found the one and only, we're outta here.
}
}
return arrSerialize.join("&");
}
This fails a few of your tests - the ones with serialized strings starting with '?' or '&'. If you feel those are valid, then you could do this at the start of the function, and all tests will pass:
if (strSerialize.length && (strSerialize[0] == '?' || strSerialize[0] == '&'))
strSerialize = strSerialize.slice(1);
Performance Comparison
I've put together a test in jsperf to compare the regex approach with this string method. It's reporting that the regex solution is 49% slower than strings, in IE10 on 32-bit Win7.
Related
I am using the the following function in javascript.
function chknumber(a) {
a.value = a.value.replace(/[^0-9.]/g, '', '');
}
This function replaces any non numeric character entered in a textbox on whose onkeyup i have called the above function. The problem is it allows this string as well
1..1
I want the function to replace the second dot character as well. Any suggestions will be helpful.
I don't advocate simplistically modifying fields while people are trying to type in them, it's just too easy to interfere with what they're doing with simple handlers like this. (Validate afterward, or use a well-written, thoroughly-tested masking library.) When you change the value of a field when the user is typing in it, you mess up where the insertion point is, which is really frustrating to the user. But...
A second replace can correct .. and such:
function chknumber(a) {
a.value = a.value.replace(/[^0-9.]/g, '').replace(/\.{2,}/g, '.');
}
That replaces two or more . in a row with a single one. But, it would still allow 1.1.1, which you probably don't want. Sadly, JavaScript doesn't have lookbehinds, so we get into more logic:
function chknumber(a) {
var str = a.value.replace(/[^0-9.]/g, '').replace(/\.{2,}/g, '.');
var first, last;
while ((first = str.indexOf(".")) !== (last = str.lastIndexOf("."))) {
str = str.substring(0, last) + str.substring(last+1);
}
if (str !== a.value) {
a.value = str;
}
}
Can't guarantee there aren't other edge cases and such, and again, every time you assign a replacement to a.value, you're going to mess up the user's insertion point, which is surprisingly frustrating.
So, yeah: Validate afterward, or use a well-written, thoroughly-tested masking library. (I've had good luck with this jQuery plugin, if you're using jQuery.)
Side note: The second '' in your original replace is unnecessary; replace only uses two arguments.
try with match method if your input is "sajan12paul34.22" the match function will return a array contain [12 , 34.22]
the array index [0] is used for getting first numeric value (12)
function chknumber(a) {
a.value = a.value.match(/[0-9]*\.?[0-9]+/g)[0];
}
So let's say the URL I have is
"mywebsite.com/file/100/"
What I want is for it to be updated to
"mywebsite.com/file/101/"
"mywebsite.com/file/102/"
(and so on...)
when the keyword cannot be found.
init();
function init()
{
searchWord("key word");
}
function searchWord(word)
{
var pageResults = document.body.innerHTML.match(word);
if(pageResults)
{
alert("word found");
} else {
}
}
Right now my script searches for a key term, and what I need is for the page to be updated by a value of 1 (100 to 101 to 102 etc) when the keyword cannot be found.
I am a noob a Javascript, none of this code is mine. I just need help developing it. I have searched around for a while, but I can't find much.
Thanks.
Not sure if this gets points for elegance.
Split the url into segments
Dispose of empty segment caused by trailing "/" if present.
If the last segment is numeric, replace it with its numeric value + 1.
Join the segments back into a string.
(If you want the trailing slash you can re-add it.)
Code
var url = "mywebsite.com/file/100/"
var segments = url.split("/");
while(segments[segments.length-1]==""){
segments.pop();
}
var lastSegment = segments[segments.length-1];
if(!isNaN(lastSegment)){
segments[segments.length-1] = (parseInt(lastSegment)+1).toString();
}
updatedUrl = segments.join("/");
One liner just for fun.
var url = window.location.hostname + window.location.pathname.split('/').map(function(sgmt){return (sgmt != '' && !isNaN(sgmt)) ? parseInt(sgmt)+1 : sgmt}).join('/');
You may want to omit the window.location.hostname to use relative url paths instead. The next piece first splits the url at the / and then uses the .map() method on the new array. The function that gets passed looks for non-blank and numerical sections of the url. If it finds it, it adds 1. When finished, it makes the array a string again (with the new number in the url) using the .join() method.
I am writing a recursive algorithm to build a finite state automaton by parsing a regular expression. The automaton iterates through the expression, pushing characters to a stack and operators to an "operator stack." When I encounter "(" (indicating a grouping operation), I push a "sub automaton" to the stack and pass the rest of the pattern to the sub automaton to parse. When that automaton encounters ")", it passes the rest of the string up to the parent automaton to finish parsing. Here is the code:
var NFA = function(par) {
this.stack = [];
this.op_stack = [];
this.parent = par;
};
NFA.prototype.parse = function(pattern) {
var done = false;
for(var i in pattern) {
if (done === true) {
break;
}
switch(pattern.charAt(i)) {
case "(":
var sub_nfa = new NFA(this);
this.stack.push(sub_nfa);
sub_nfa.parse(pattern.substring(i+1, pattern.length));
done = true;
break;
case ")":
if (this.parent !== null) {
var len = pattern.length;
/*TROUBLE SPOT*/
this.parent.parse(pattern.substring(i, pattern.length));
done = true;
break;
}
case "*":
this.op_stack.push(operator.KLEENE);
break;
case "|":
this.op_stack.push(operator.UNION);
break;
default:
if(this.stack.length > 0) {
//only push concat after we see at least one symbol
this.op_stack.push(operator.CONCAT);
}
this.stack.push(pattern.charAt(i));
}
}
};
Note the area marked "TROUBLE SPOT". Given the regular expression "(a|b)a", the call this.parent.parse, is called exactly once: when the sub-automaton encounters ")". At this point, pattern.substring(i, pattern.length) = ")a". This "works", but it isn't correct because I need to consume the ")" input before I pass the string to the parent automaton. However, if I change the call to this.parent.parse(pattern.substring(i+1, pattern.length), parse gets handed the empty string! I have tried stepping through the code and I cannot explain this behavior. What am I missing?
At Juan's suggestion, I made a quick jsfiddle to show the problem when trying to parse "(a|b)a" with this algorithm. In the ")" case, it populates an empty div with the substring at the i index and the substring at the i+1 index. It shows that while there are 2 characters in the substring at i, the substring at i+1 is the empty string! Here's the link: http://jsfiddle.net/XC6QM/1/
EDIT: I edited this question to reflect the fact that using charAt(i) doesn't change the behavior of the algorithm.
I think the previous answer was on the right track. But there also looks to me to be an off-by-one error. Shouldn't you be increasing the index for your substring? You don't want to include the ")" in the parent parse, right?
this.parent.parse(pattern.substring(i + 1, pattern.length));
But this will still fail because of the error Juan mentioned. A quick temporary fix to test this would be to convert the i to a number:
this.parent.parse(pattern.substring(+i + 1, pattern.length));
This might do it for you. But you should probably go back and switch away from the for-in loop on the string. I think that's causing your issue. Turn it into an array with str.split('') and then use an integer to loop. That will prevent further such issues.
The real problem is the fact that you were using a for in to iterate through the characters of the string. With the for in loop, your i is going to be a string, therefore, when you try to do i+1, it does string concatenation.
If you change your iteration to be
for(var i=0; i < pattern.length; i++) {
Then it all works fine http://jsfiddle.net/XC6QM/2/
Scott's answer correctly identified the problem but I think his solution (converting the indexes to numbers) is not ideal. You're better off looping with a numeric index to begin with
Also, you should not use brackets to access characters within a string, that does not work in IE 7
switch(pattern[i]) {
should be
switch(pattern.charAt(i)) {
I want to find the number of tabs at the beginning of a string (and of course I want it to be fast running code ;) ). This is my idea, but not sure if this is the best/fastest choice:
//The regular expression
var findBegTabs = /(^\t+)/g;
//This string has 3 tabs and 2 spaces: "<tab><tab><space>something<space><tab>"
var str = " something ";
//Look for the tabs at the beginning
var match = reg.exec( str );
//We found...
var numOfTabs = ( match ) ? match[ 0 ].length : 0;
Another possibility is to use a loop and charAt:
//This string has 3 tabs and 2 spaces: "<tab><tab><space>something<space><tab>"
var str = " something ";
var numOfTabs = 0;
var start = 0;
//Loop and count number of tabs at beg
while ( str.charAt( start++ ) == "\t" ) numOfTabs++;
In general if you can calculate the data by simply iterating through the string and doing a character check at every index, this will be faster than a regex/regular expression which must build up a more complex searching engine. I encourage you to profile this but I think you'll find the straight search is faster.
Note: Your search should use === instead of == here as you don't need to introduce conversions in the equality check.
function numberOfTabs(text) {
var count = 0;
var index = 0;
while (text.charAt(index++) === "\t") {
count++;
}
return count;
}
Try using a profiler (such as jsPerf or one of the many available backend profilers) to create and run benchmarks on your target systems (the browsers and/or interpreters you plan to support for your software).
It's useful to reason about which solution will perform best based on your expected data and target system(s); however, you may sometimes be surprised by which solution actually performs fastest, especially with regard to big-oh analysis and typical data sets.
In your specific case, iterating over characters in the string will likely be faster than regular expression operations.
One-liner (if you find smallest is best):
"\t\tsomething".split(/[^\t]/)[0].length;
i.e. splitting by all non-tab characters, then fetching the first element and obtaining its length.
i am trying to validate if a certain company was already picked for an application. the companyList format is:
60,261,420 ( a list of companyID)
I used
cID = $('#coName').val().split('::')[1];
to get the id only.
I am calling this function by passing say 60:
findCompany = function(value) {
var v = /^.+60,261,420$/.test(value);
alert(v);
}
when I pass the exact same string, i get false. any help?
Well if your company list is a list of numeric IDs like that, you need to make the resulting regular expression actually be the correct expression — if that's even the way you want to do it.
Another option is to just make an array, and then test for the value being in the array.
As a regex, though, what you could do is this:
var companyList = [<cfoutput> whatever </cfoutput>]; // get company ID list as an array of numbers
var companyRegex = new RegExp("^(?:" + companyList.join('|') + ")$");
Then you can say:
function findCompany(id) {
if (companyRegex.test(id)) alert(id + " is already in the list!");
}
Why not split the string into an array, like you did for your testing, iterate over the list and check if it's in?
A regexp just for that is balls, overhead and slower. A lot.
Anyway, for your specific question:
You’re checking the string "60" for /^.+60,261,420$/.
.+60 will obviously not match because you require at least one character before the 60. The commas also evaluate and are not in your String.
I don’t quite get where your regexp comes from.
Were you looking for a regexp to OR them a hard-coded list of IDs?
Code for splitting it and checking the array of IDs:
findCompany = function(value) {
$('#coName').val().split('::').each(function(val){
if(val == value) return true;
});
return false;
}