javascript regex search start of every word and following word - javascript

I'm trying to write a regex based on user input that searches the start of every word and the following word (excluding the space) in a string. This is the current code i am using.
var ndl = 'needlehay', //user input
re = new RegExp('(?:^|\\s)' + ndl, 'gi'), //searches start of every word
haystack = 'needle haystack needle second instance';
re.test(haystack); //the regex i need should find 'needle haystack'
Any help or suggestions i'd gladly appreciate.
Thanks!

I'd iterate over the needle, and try each variation manually
function check(needle, haystack) {
if (haystack.replace(/\s/g, '').indexOf(needle) === 0) return true;
return needle.split('').some(function(char, i, arr) {
var m = (i===0 ? '' : ' ') + needle.slice(0,i) +' '+ needle.slice(i);
return haystack.indexOf(m) != -1;
});
}

Related

Recombine capture groups in single regexp?

I am trying to handle input groups similar to:
'...A.B.' and want to output '.....AB'.
Another example:
'.C..Z..B.' ==> '......CZB'
I have been working with the following:
'...A.B.'.replace(/(\.*)([A-Z]*)/g, "$1")
returns:
"....."
and
'...A.B.'.replace(/(\.*)([A-Z]*)/g, "$2")
returns:
"AB"
but
'...A.B.'.replace(/(\.*)([A-Z]*)/g, "$1$2")
returns
"...A.B."
Is there a way to return
"....AB"
with a single regexp?
I have only been able to accomplish this with:
'...A.B.'.replace(/(\.*)([A-Z]*)/g, "$1") + '...A.B.'.replace(/(\.*)([A-Z]*)/g, "$2")
==> ".....AB"
If the goal is to move all of the . to the beginning and all of the A-Z to the end, then I believe the answer to
with a single regexp?
is "no."
Separately, I don't think there's a simpler, more efficient way than two replace calls — but not the two you've shown. Instead:
var str = "...A..B...C.";
var result = str.replace(/[A-Z]/g, "") + str.replace(/\./g, "");
console.log(result);
(I don't know what you want to do with non-., non-A-Z characters, so I've ignored them.)
If you really want to do it with a single call to replace (e.g., a single pass through the string matters), you can, but I'm fairly sure you'd have to use the function callback and state variables:
var str = "...A..B...C.";
var dots = "";
var nondots = "";
var result = str.replace(/\.|[A-Z]|$/g, function(m) {
if (!m) {
// Matched the end of input; return the
// strings we've been building up
return dots + nondots;
}
// Matched a dot or letter, add to relevant
// string and return nothing
if (m === ".") {
dots += m;
} else {
nondots += m;
}
return "";
});
console.log(result);
That is, of course, incredibly ugly. :-)

Capitalizing a String

I'm aware of the CSS attribute text-transform: capitalize but can anyone help me with replicating this using Javascript?
I would like to pass an argument to my function which will return the string with the first letter of each word capitalized.
I've got this far but I'm stuck trying to break my array of strings in to chunks:
function upper(x){
x = x.split(" ");
// this function should return chunks but when called I'm getting undefined
Array.prototype.chunk = function ( n ) {
return [ this.slice( 0, n ) ].concat( this.slice(n).chunk(n) );
};
x = x.chunk;
}
upper("chimpanzees like cigars")
after the chunk I'm guessing I need to again split each chunk in to the first character and the remaining characters, use .toUpperCase() on the first character, join it back up with the remaining and then join up the chunks again in to a string?
Is there a simpler method for doing this?
I came up with a solution for both a single word and also for an array of words. It will also ensure that all other letters are lowercase for good measure. I used the Airbnb style guide as well. I hope this helps!
const mixedArr = ['foo', 'bAr', 'Bas', 'toTESmaGoaTs'];
const word = 'taMpa';
function capitalizeOne(str) {
return str.charAt(0).toUpperCase().concat(str.slice(1).toLowerCase());
}
function capitalizeMany(args) {
return args.map(e => {
return e.charAt(0).toUpperCase().concat(e.slice(1).toLowerCase());
});
};
const cappedSingle = capitalizeOne(word);
const cappedMany = capitalizeMany(mixedArr);
console.log(cappedSingle);
console.log(cappedMany);
The map function is perfect for this.
w[0].toUpperCase() : Use this to capitalize the first letter of each word
w.slice(1): Return the string from the second character on
EDGE Case
If the user doesn't enter a string, the map function will not work and an error will be raised. This can be guarded against by checking if the user actually entered something.
var userInput = prompt("Enter a string");
var capitalizedString = userInput == "" ? "Invalid String" :
userInput.split(/\s+/).map(w => w[0].toUpperCase() + w.slice(1)).join(' ');
console.log(capitalizedString);
You can use the following solution which doesn't use regex.
function capitalize(str=''){
return str.trim().split('')
.map((char,i) => i === 0 ? char.toUpperCase() : char )
.reduce((final,char)=> final += char, '' )
}
capitalize(' hello') // Hello
"abcd efg ijk lmn".replace(/\b(.)/g, (m => m.toUpperCase())) // Abcd Efg Ijk Lmn
You may want to try a regex approach:
function upperCaseFirst(value) {
var regex = /(\b[a-z](?!\s))/g;
return value ? value.replace(regex, function (v) {
return v.toUpperCase();
}) : '';
}
This will grab the first letter of every word on a sentence and capitalize it, but if you only want the first letter of the sentence, you can just remove the g modifier at the end of the regex declaration.
or you could just iterate the string and do the job:
function capitalize(lowerStr){
var result = "";
var isSpacePrevious = false;
for (var i=0; i<lowerStr.length; i++){
if (i== 0 || isSpacePrevious){
result += lowerStr[i].toUpperCase();
isSpacePrevious = false;
continue;
}
if (lowerStr[i] === ' '){
isSpacePrevious = true;
}
result += lowerStr[i];
}
return result;
}

If condition that pushes values that contain/match a string

I have a nicely functioning full calendar script. I have some filters for it, which basically have the following form:
$("input[name='event_filter_select']:checked").each(function () {
// I specified data-type attribute in HTML checkboxes to differentiate
// between risks and tags.
// Saving each type separately
if ($(this).data('type') == 'risk') {
risks.push($(this).val());
} else if ($(this).data('type') == 'tag') {
tagss.push($(this).val());
}
});
However the else if statement should check if the checked value 'tag' is contained within the result set, not be the only value of the result set (as implied by the ==).
Now I can only filter results that have the checked tag-value only. But i want to filter those, which have the tag-value amongst many others.
I figure this is to be done with match(/'tag'/) but i cannot figure out for the life of me how to put that into an if-statement.
Would be really glad if someone could lead me in the right direction.
I would simply do:
...
if ($(this).data('type') == 'risk') {
risks.push($(this).val());
} else if ($(this).data('type').test(/^tag/) {
tagss.push($(this).val());
}
...
This works if the 'tag' must be at the beginning of the string.
If the 'tag' can be everywhere in the string, you can use test(/tag/).
If your data is a string, example: tag filter1 filter2 filter3, you could use the indexOf-function (manual)
Code:
if ($(this).data('type').indexOf("risk") != -1))
//Action here.
indexOf returns -1 if the text isn't found.
You can use:
var re = new RegExp('\\b' + word + '\\b', 'i');
or if you wish to have the word hard-coded in (e.g., in the example, the word test):
var re = /\btest\b/i
Example showing the matches below:
var input = document.querySelector('input');
var div = document.querySelector('div');
var re;
var match;
input.addEventListener('keyup', function() {
match = input.value.trim();
re = new RegExp('\\b' + match + '\\b', 'i');
if($('div').data('type').match(re))
div.innerHTML = 'Matched the word: ' + '<strong>' + match + '</strong>';
else div.innerHTML = 'Did not match the word: ' + '<strong>' + match + '</strong>';
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Word to match:<input></input><br>
Output:
<div data-type='tag tags test'></div>
With the above regular expression incorporated into your code, it should look something like this:
else if ($(this).data('type').match(/\btag\b/i) { //true for data-type that has `tag` in it.
tagss.push($(this).val());
}
Try with this condition.
/\btag\b/.test($(this).data('type'))

Remove all dots except the first one from a string

Given a string
'1.2.3.4.5'
I would like to get this output
'1.2345'
(In case there are no dots in the string, the string should be returned unchanged.)
I wrote this
function process( input ) {
var index = input.indexOf( '.' );
if ( index > -1 ) {
input = input.substr( 0, index + 1 ) +
input.slice( index ).replace( /\./g, '' );
}
return input;
}
Live demo: http://jsfiddle.net/EDTNK/1/
It works but I was hoping for a slightly more elegant solution...
There is a pretty short solution (assuming input is your string):
var output = input.split('.');
output = output.shift() + '.' + output.join('');
If input is "1.2.3.4", then output will be equal to "1.234".
See this jsfiddle for a proof. Of course you can enclose it in a function, if you find it necessary.
EDIT:
Taking into account your additional requirement (to not modify the output if there is no dot found), the solution could look like this:
var output = input.split('.');
output = output.shift() + (output.length ? '.' + output.join('') : '');
which will leave eg. "1234" (no dot found) unchanged. See this jsfiddle for updated code.
It would be a lot easier with reg exp if browsers supported look behinds.
One way with a regular expression:
function process( str ) {
return str.replace( /^([^.]*\.)(.*)$/, function ( a, b, c ) {
return b + c.replace( /\./g, '' );
});
}
You can try something like this:
str = str.replace(/\./,"#").replace(/\./g,"").replace(/#/,".");
But you have to be sure that the character # is not used in the string; or replace it accordingly.
Or this, without the above limitation:
str = str.replace(/^(.*?\.)(.*)$/, function($0, $1, $2) {
return $1 + $2.replace(/\./g,"");
});
You could also do something like this, i also don't know if this is "simpler", but it uses just indexOf, replace and substr.
var str = "7.8.9.2.3";
var strBak = str;
var firstDot = str.indexOf(".");
str = str.replace(/\./g,"");
str = str.substr(0,firstDot)+"."+str.substr(1,str.length-1);
document.write(str);
Shai.
Here is another approach:
function process(input) {
var n = 0;
return input.replace(/\./g, function() { return n++ > 0 ? '' : '.'; });
}
But one could say that this is based on side effects and therefore not really elegant.
This isn't necessarily more elegant, but it's another way to skin the cat:
var process = function (input) {
var output = input;
if (typeof input === 'string' && input !== '') {
input = input.split('.');
if (input.length > 1) {
output = [input.shift(), input.join('')].join('.');
}
}
return output;
};
Not sure what is supposed to happen if "." is the first character, I'd check for -1 in indexOf, also if you use substr once might as well use it twice.
if ( index != -1 ) {
input = input.substr( 0, index + 1 ) + input.substr(index + 1).replace( /\./g, '' );
}
var i = s.indexOf(".");
var result = s.substr(0, i+1) + s.substr(i+1).replace(/\./g, "");
Somewhat tricky. Works using the fact that indexOf returns -1 if the item is not found.
Trying to keep this as short and readable as possible, you can do the following:
JavaScript
var match = string.match(/^[^.]*\.|[^.]+/g);
string = match ? match.join('') : string;
Requires a second line of code, because if match() returns null, we'll get an exception trying to call join() on null. (Improvements welcome.)
Objective-J / Cappuccino (superset of JavaScript)
string = [string.match(/^[^.]*\.|[^.]+/g) componentsJoinedByString:''] || string;
Can do it in a single line, because its selectors (such as componentsJoinedByString:) simply return null when sent to a null value, rather than throwing an exception.
As for the regular expression, I'm matching all substrings consisting of either (a) the start of the string + any potential number of non-dot characters + a dot, or (b) any existing number of non-dot characters. When we join all matches back together, we have essentially removed any dot except the first.
var input = '14.1.2';
reversed = input.split("").reverse().join("");
reversed = reversed.replace(\.(?=.*\.), '' );
input = reversed.split("").reverse().join("");
Based on #Tadek's answer above. This function takes other locales into consideration.
For example, some locales will use a comma for the decimal separator and a period for the thousand separator (e.g. -451.161,432e-12).
First we convert anything other than 1) numbers; 2) negative sign; 3) exponent sign into a period ("-451.161.432e-12").
Next we split by period (["-451", "161", "432e-12"]) and pop out the right-most value ("432e-12"), then join with the rest ("-451161.432e-12")
(Note that I'm tossing out the thousand separators, but those could easily be added in the join step (.join(','))
var ensureDecimalSeparatorIsPeriod = function (value) {
var numericString = value.toString();
var splitByDecimal = numericString.replace(/[^\d.e-]/g, '.').split('.');
if (splitByDecimal.length < 2) {
return numericString;
}
var rightOfDecimalPlace = splitByDecimal.pop();
return splitByDecimal.join('') + '.' + rightOfDecimalPlace;
};
let str = "12.1223....1322311..";
let finStr = str.replace(/(\d*.)(.*)/, '$1') + str.replace(/(\d*.)(.*)/, '$2').replace(/\./g,'');
console.log(finStr)
const [integer, ...decimals] = '233.423.3.32.23.244.14...23'.split('.');
const result = [integer, decimals.join('')].join('.')
Same solution offered but using the spread operator.
It's a matter of opinion but I think it improves readability.

Why is my RegExp ignoring start and end of strings?

I made this helper function to find single words, that are not part of bigger expressions
it works fine on any word that is NOT first or last in a sentence, why is that?
is there a way to add "" to regexp?
String.prototype.findWord = function(word) {
var startsWith = /[\[\]\.,-\/#!$%\^&\*;:{}=\-_~()\s]/ ;
var endsWith = /[^A-Za-z0-9]/ ;
var wordIndex = this.indexOf(word);
if (startsWith.test(this.charAt(wordIndex - 1)) &&
endsWith.test(this.charAt(wordIndex + word.length))) {
return wordIndex;
}
else {return -1;}
}
Also, any improvement suggestions for the function itself are welcome!
UPDATE: example: I want to find the word able in a string, I waht it to work in cases like [able] able, #able1 etc.. but not in cases that it is part of another word like disable, enable etc
A different version:
String.prototype.findWord = function(word) {
return this.search(new RegExp("\\b"+word+"\\b"));
}
Your if will only evaluate to true if endsWith matches after the word. But the last word of a sentence ends with a full stop, which won't match your alphanumeric expression.
Did you try word boundary -- \b?
There is also \w which match one word character ([a-zA-Z_]) -- this could help you too (depends on your word definition).
See RegExp docs for more details.
If you want your endsWith regexp also matches the empty string, you just need to append |^$ to it:
var endsWith = /[^A-Za-z0-9]|^$/ ;
Anyway, you can easily check if it is the beginning of the text with if (wordIndex == 0), and if it is the end with if (wordIndex + word.length == this.length).
It is also possible to eliminate this issue by operating on a copy of the input string, surrounded with non-alphanumerical characters. For example:
var s = "#" + this + "#";
var wordIndex = this.indexOf(word) - 1;
But I'm afraid there is another problems with your function:
it would never match "able" in a string like "disable able enable" since the call to indexOf would return 3, then startsWith.test(wordIndex) would return false and the function would exit with -1 without searching further.
So you could try:
String.prototype.findWord = function (word) {
var startsWith = "[\\[\\]\\.,-\\/#!$%\\^&\*;:{}=\\-_~()\\s]";
var endsWith = "[^A-Za-z0-9]";
var wordIndex = ("#"+this+"#").search(new RegExp(startsWith + word + endsWith)) - 1;
if (wordIndex == -1) { return -1; }
return wordIndex;
}

Categories

Resources