Related
The emphasis here is on the word exactly. This needs to work for any number of permutations, so hopefully my example is clear enough.
Given a string of random letters, is it possible (using RegEx) to match an exact number of letters within the given string?
So if I have a string (str1) containing letters ABZBABJDCDAZ and I wanted to match the letters JDBBAA (str2), my function should return true because str1 contains all the right letters enough times. If however str1 were to be changed to ABAJDCDA, then the function would return false as str2 requires that str1 have at least 2 instances of the letter B.
This is what I have so far using a range:
const findLetters = (str1, str2) => {
const regex = new RegExp(`[${str2}]`, 'g')
const result = (str1.match(regex))
console.log(result)
}
findLetters('ABZBABJDCDAZ', 'JDBBAA')
As you can see it matches the right letters, but it matches all instances of them. Is there any way to do what I'm trying to do using RegEx? The reason I'm focusing on RegEx here is because I need this code to be highly optimised, and so far my other functions using Array.every() and indexOf() are just too slow.
Note: My function only requires to return a true/false value.
Try (here we sort letters of both strings and then create regexp like A.*A.*B.*B.*D.*J)
const findLetters = (str1, str2) => {
const regex = new RegExp([...str2].sort().join`.*`)
return regex.test([...str1].sort().join``)
}
console.log( findLetters('ABZBABJDCDAZ', 'JDBBAA') );
console.log( findLetters('ABAJDCDA', 'JDBBAA') );
I dont know if regex is the right way for this as this can also get very expensive. Regex is fast, but not always the fastest.
const findLetters2 = (strSearchIn, strSearchFor) => {
var strSearchInSorted = strSearchIn.split('').sort(function(a, b) {
return a.localeCompare(b);
});
var strSearchForSorted = strSearchFor.split('').sort(function(a, b) {
return a.localeCompare(b);
});
return hasAllChars(strSearchInSorted, strSearchForSorted);
}
const hasAllChars = (searchInCharList, searchCharList) => {
var counter = 0;
for (i = 0; i < searchCharList.length; i++) {
var found = false;
for (counter; counter < searchInCharList.length;) {
counter++;
if (searchCharList[i] == searchInCharList[counter - 1]) {
found = true;
break;
}
}
if (found == false) return false;
}
return true;
}
// No-Regex solution
console.log('true: ' + findLetters2('abcABC', 'abcABC'));
console.log('true: ' + findLetters2('abcABC', 'acbACB'));
console.log('true: ' + findLetters2('abcABCx', 'acbACB'));
console.log('false: ' + findLetters2('abcABC', 'acbACBx'));
console.log('true: ' + findLetters2('ahfffmbbbertwcAtzrBCasdf', 'acbACB'));
console.log('false: ' + findLetters2('abcABC', 'acbAACB'));
Feel free to test it's speed and to optimize it as I'm no js expert. This solution should iterate each string once after sorting. Sorting is thanks to https://stackoverflow.com/a/51169/9338645.
How can I build a regular expression that will replace each comma with a '.' decimal point if there are more than 3 or less than 3 digits.
that is 4,444 is correct and stay like that but 3,33 will be 3.33 or 4,4444 will be 4.444
similarly it can be like this as well 1,234,45,6789, and it should become 1,234.45.6789
function commaToDot(number) {
let regex = /^\d{1,3}(?:\,\d{3})*((?:,\d+)+)*?$/;
let matches = number.match(regex);
if (matches[1]) {
number = number.replace(matches[1], matches[1].replace(/,/g, '.'))
}
return number;
}
console.log(commaToDot('4,4444'));
console.log(commaToDot('5,555'));
console.log(commaToDot('3,33'));
console.log(commaToDot('1,234,45,6789'));
console.log(commaToDot('1,234,45,678,9'));
console.log(commaToDot('5,5,5,5,5'));
This will match everything after the numbers stop being part of the \d{1,3},\d{3} pattern, and replace their commas with dots.
From what I gather, this is what you are looking for.
Edit
After leaving my comment above to check validity of "1,333.22,333", I've had to re-write the regex slightly:
function commaToDot(number) {
let regex = /(?!,\d{3},)(,\d{0,2})|(,\d{4,})/g,
matches = number.match(regex);
if (matches) {
matches.forEach((match) => {
number = number.replace(match, match.replace(/,/g, '.'));
});
}
return number
}
console.log(commaToDot('1,234,45,678,9'));
console.log(commaToDot('4,4444'));
console.log(commaToDot('5,555'));
console.log(commaToDot('3,33'));
console.log(commaToDot('1,234,45,6789'));
console.log(commaToDot('5,5,5,5,5'));
console.log(commaToDot('12,345,678,90'));
This should now do what you would like it to do.
With RegExp.test() function and specific regex patterns:
var commaToDot = function(str){
if (/^-?\d+[,\d]+\d+$/.test(str) && /\d+,(\d{1,2}|\d{4,})\b/.test(str)){
var parts = str.split(',');
return parts.length > 2? parts[0] +','+ parts.slice(1).join('.') : parts.join('.');
} else {
return str;
}
};
console.log(commaToDot('4,4444'));
console.log(commaToDot('5,555'));
console.log(commaToDot('3,33'));
console.log(commaToDot('1,234,45,6789'));
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 the string contains any characters besides a number or the comma that separates it from the other character the function should return "invalid input", if they're all numbers it should output "great job"
a,4,3,# = "invalid input"...
1,4,6,5 = "great job" <===returned from function
I'm trying to learn about regex but if you could do it using another method that's ok. I'm interested in how you would go about solving it. I couldn't find an answer online my self. I searched. I know that d(regex) is for digits but I just don't now how to apply it for this case.
You can use a simple regular expression to check that the string contains only comma separated numbers:
/^(\d+,)*\d+$/.test(s)
And use it like:
['1,2,3','123,5,223','1#32','12','12,',',23',','].forEach(function(s) {
document.write('<br>' + s + ' : ' + (/^(\d+,)*\d+$/.test(s)? 'great job' : 'invalid input'));
});
This assumes that numbers can have any number of digits and that commas are only allowed between numbers; not at the start, end or consecutively.
You can split a string into an array on a character using String.split(char), for example:
'1,4,6,5'.split(',');
> [1, 4, 6, 5]
You could then use a regex to check if the character is a number and a reducer to validate.
function valid(c) {
//using regex, return true if the character is valid, false if not
// or something like
return !Number.isNaN(+c);
}
'1,4,6,5'.split(',').reduce(function(acc, x) {
if valid(x) {
return acc;
} else {
return false;
}
}, true);
that should give you a boolean that you can map to your desired output string. reduce works sort of like a loop, it passes an accumulated value and each element of the array one at a time, with the inital value given as at the part here '}, true);' so as long as the regex returns true, we keep returning the same acc value, but if we get an invalid regex we switch the accumulator to false. note that because we don't change the accumulator value on valid inputs, we don't have to worry about it suddenly reventing back to a 'valid' status.
You can use the Array.prototype.every() method
return str.split(',').every(function(val) {
return parseInt(val) == val; // or any of the many other ways to check if a string is a number
});
Helpful links:
Check whether an input string contains number
Check if string contains only digits
I threw this together, hopefully it helps!
It is a working function, like you asked.
function isOnlyNumsAndCommas(str) {
for (var i = 2; i <= str.length + 2; i += 2) {
var val = str.substring(i - 2, i - 1);
var isnum = val.match(/\d+/g);
if (!isnum) {
return ('invalid input');
break;
}
}
return('great job');
}
alert(isOnlyNumsAndCommas("#,4,3,3"));
For a non 'for loop' function!
function isOnlyNumsAndCommas(str) {
if (str.match(/[^\d|,]/) === null) {
return('great job');
} else {
return('invalid input');
}
}
alert(isOnlyNumsAndCommas("a,4,3,#"));
function isValid(str){
var res = str.split(',').every(function(item){
return !isNaN(item) ? true : false;
});
return res ? "great job" : "invalid input";
}
console.log(isValid("1,2,4,5,#"))
var hasCommaSeparatedDigits = function(str){
var strArr = str.split(",");
var res = strArr.length ? "Great job!" : "Invalid Input";
for(var i in strArr){
var ch = strArr[i];
if(isNaN(ch)){
res = "Invalid Input";
break;
}
}
return res;
}
console.log(hasCommaSeparatedDigits("1,2,3,4"));
console.log(hasCommaSeparatedDigits("1,a,3,4"));
There is no need to split the string, loop and check for validity of each part. Just do a regex check for presence of a non-digit excluding the comma
(this assumes that a comma can occur anywhere)
try:
var str = "1,2,3,";
if(str.match(/[^\d|,]/) == null)
alert("great job");
else
alert("err");
For example suppose I always have a string that is delimited by "-". Is there a way to transform
it-is-a-great-day-today
to
itIsAGreatDayToday
Using RegEx?
Yes (edited to support non-lowercase input and Unicode):
function camelCase(input) {
return input.toLowerCase().replace(/-(.)/g, function(match, group1) {
return group1.toUpperCase();
});
}
See more about "replace callbacks" on MDN's "Specifying a function as a parameter" documentation.
The first argument to the callback function is the full match, and subsequent arguments are the parenthesized groups in the regex (in this case, the character after the the hyphen).
Another method using reduce:
function camelCase(str) {
return str
.split('-')
.reduce((a, b) => a + b.charAt(0).toUpperCase() + b.slice(1));
}
You can match on the word character after each dash (-) or the start of the string, or you could simplify by matching the word character after each word boundary (\b):
function camelCase(s) {
return (s||'').toLowerCase().replace(/(\b|-)\w/g, function(m) {
return m.toUpperCase().replace(/-/,'');
});
}
camelCase('foo-bar'); // => 'FooBar'
camelCase('FOo-BaR-gAH'); // => 'FooBarGah'
Here's a demo
var test = 'It-is-a-great-day-today';
function camelize(str) {
return str[0].toLowerCase() + str.replace(/-([a-z])/g, function(a, b) {
return b.toUpperCase();
}).slice(1);
}
console.log(camelize(test));
This should also work:
function camelCase(str) {
return str.replace(/^.|-./g, function(letter, index) {
return index == 0 ? letter.toLowerCase() : letter.substr(1).toUpperCase();
});
}
And IMHO it is little bit more efficient since we're not converting whole input string to lowercase first and then convert to uppercase if needed. This function only converts first letter to lowercase and then every character after hyphen - to uppercase.
See http://jsfiddle.net/54ZcM/
function camelCase(string) {
return string.toLowerCase().replace(/(\-[a-zA-Z])/g, function($1) {
return $1.toUpperCase().replace('-','');
})
}
alert(camelCase('fOo-BarBA-fo'));
I know this question is a bit old but,
Here's my version of camelCase function:
var camelCase = (function () {
var DEFAULT_REGEX = /[-_]+(.)?/g;
function toUpper(match, group1) {
return group1 ? group1.toUpperCase() : '';
}
return function (str, delimiters) {
return str.replace(delimiters ? new RegExp('[' + delimiters + ']+(.)?', 'g') : DEFAULT_REGEX, toUpper);
};
})();
It handles all of the following edge cases:
takes care of both underscores and hyphens by default (configurable with second parameter)
string with unicode characters
string that ends with hyphens or underscore
string that has consecutive hyphens or underscores
Here's a link to live tests: http://jsfiddle.net/avKzf/2/
Here are results from tests:
input: "ab-cd-ef", result: "abCdEf"
input: "ab-cd-ef-", result: "abCdEf"
input: "ab-cd-ef--", result: "abCdEf"
input: "ab-cd--ef--", result: "abCdEf"
input: "--ab-cd--ef--", result: "AbCdEf"
input: "--ab-cd-__-ef--", result: "AbCdEf"
Notice that strings that start with delimiters will result in a uppercase letter at the beginning.
If that is not what you would expect, you can always use lcfirst.
Here's my lcfirst if you need it:
function lcfirst(str) {
return str && str.charAt(0).toLowerCase() + str.substring(1);
}
This works great but someone might be able to clean it up.
var toCamelCase = function(str) {
// Replace special characters with a space
str = str.replace(/[^a-zA-Z0-9 ]/g, " ");
// put a space before an uppercase letter
str = str.replace(/([a-z](?=[A-Z]))/g, '$1 ');
// Lower case first character and some other stuff that I don't understand
str = str.replace(/([^a-zA-Z0-9 ])|^[0-9]+/g, '').trim().toLowerCase();
// uppercase characters preceded by a space or number
str = str.replace(/([ 0-9]+)([a-zA-Z])/g, function(a,b,c) {
return b.trim() + c.toUpperCase();
});
return str;
};
console.log(toCamelCase('hyphen~name~ format'));
console.log(toCamelCase('hyphen.name.format'));
console.log(toCamelCase('hyphen-name-format'));
console.log(toCamelCase('Hyphen-Dame-Gormat'));
console.log(toCamelCase('EquipmentClass name'));
console.log(toCamelCase('Equipment className'));
console.log(toCamelCase('equipment class name'));
console.log(toCamelCase(' e Equipment Class Name'));
console.log(toCamelCase('under9score_name_format'));
console.log(toCamelCase('Enderscore_name_format'));
console.log(toCamelCase('EnderscoreBameFormat'));
console.log(toCamelCase('_EnderscoreBameFormat'));
http://jsbin.com/yageqi/1/edit?js,console
'it-is-a-great-day-today'.split('-').map(function(x,i){
return (i?x[0].toUpperCase():x[0]) + x.slice(1).toLowerCase()
}).join('')
Result:
'itIsAGreatDayToday'
Alternatively, .match(/\w+/g) rather than .split('-') -- depending on what you want to do in edge cases like "this--is-a-test".
var string = "it-is-a-great-day-today";
or
var string = "it_is_a_great_day_today";
var regex = /(_|-)([a-z])/g;
string.toLowerCase().replace(regex, toCamelCase );
function toCamelCase( string ){
return string[1].toUpperCase();
}
Output: "itIsAGreatDayToday";
here is the jsfiddle you can play with to test this
http://jsfiddle.net/5n84w/2/
```
/**
* Function to convert any string to camelCase
* var regex = 'chetan-Ankola###.com---m13ok#-#alo(*finding!R%S#%-GFF';
* Where [-_ .] is the seperator, you can add eg: '#' too
* + is to handle repetition of seperator
* ? is to take care of preceeding token
* match nov(ember)? matches nov and november
*/
var camelCaser = function (str) {
var camelCased = str.replace(/[-_ .]+(.)?/g, function (match, p) {
if (p) {
return p.toUpperCase();
}
return '';
}).replace(/[^\w]/gi, '');
return camelCased;
};
```
lodash.camelCase can be another option
Sample:
const str = 'it-is-a-great-day-today';
lodash.camelCase(str.split('-'));
result: itIsAGreatDayToday
Better do this guys,
function camelCase(data) {
var tmp;
if (data && typeof data === 'object') {
forEach(data, function (value, key) {
var tmpvalue = camelCase(key);
tmp[tmpvalue] = value;
});
return tmp;
} else {
return data.toLowerCase().replace(/(\_\w)/g, function (m) { return m[1].toUpperCase() }).replace(/(\-\w)/g, function (m) { return m[1].toUpperCase(); });
}
}
console.log(camelCase("SucCCCess_dfds_dsqsdqs-dsdqs-dqsdqs"));
Works perfectly in any cases.
$scope.toCamelCase = function(arg){
var arg = arg.toLowerCase();
var arr = arg.split("");
arr[0] = arr[0].toUpperCase();
return arr.join("");
};