I was using javascript to detect for specific key strokes and while writing the method I thought I'd try regular expressions and the test() method and came up with:
if (/8|9|37|38|46|47|48|49|50|51|52|53|54|55|56|57|96|97|98|99|100|101|102|103|104|105|110/.test(num)) {
// do something if there's a match
}
This doesn't seem to work 100% as some values seem to make it past the regex test, such as 83. I've since moved on, but I'm still curious as to why this didn't work.
This is the completely wrong way to do it.
To answer the question, the regex is matching part of your string. The string 83 passes by matching the 8.
You need to anchor your regex by putting ^( at the beginning and )$ at the end.
The correct way to do this is to make an array of valid numbers, and compare using parseInt.
For example:
var validNumbers = [ 8, 9, 37, 38, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 110 ];
if (validNumbers.indexOf(parseInt(num, 10)) >=0 ) {
//Match
}
You'll need an indexOf function for IE:
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(needle) {
for(var i = 0; i < this.length; i++) {
if(this[i] === needle) {
return i;
}
}
return -1;
};
}
You need to specify the start and end of the string. Otherwise 8 in 8|… will match the 8 in 83:
/^(8|9|37|38|46|47|48|49|50|51|52|53|54|55|56|57|96|97|98|99|100|101|102|103|104|105|110)$/.test(num)
But you should rather use numeric comparison. If you don’t like to list every number, you can use ranges like this:
function foo(number, numbers) {
for (var i=0; i<numbers.length; ++i) {
if (numbers[i] === number) {
return true;
} else if (numbers[i].constructor === Array) {
if (numbers[i][0] <= number && number <= numbers[i][1]) {
return true;
}
}
}
return false;
}
var numbers = [8, 9, 37, 38, [46, 57], [96, 105], 110];
if (foo(num, numbers)) {
// …
}
If you make a regular expresion like /\b(100|101)/g it will match only 100 and 101 and not 5100, 5101 or ...101...;
The only problem with this is if your are using negative numbers, e.g in case of 101 and -101 both match with the regexp.
I know this because is what I'm facing and want to avoid.
I can share with you an example:
let array = [89, 7, 92, 78, 899, 65, 56, 92, 922, 292, 289, 389, 2879, 2932, 8999];
I want to find how many instances of the number 92 exist in that array. Therefore I am searching for the precise number of 92. And I want to use Regular Expressions in Javascript.
First part comes with the transformation of the array into a string:
let strCheck = array.toString(); // "89,7,92,78,899,65,56,92,922,292,289,389,2879,2932,8999"
let regex = /\b92\b/g;
I used the flag g for global so that it finds all the matches and the \b word boundary as described in MDN.
let arrResult = strCheck.match(regex); // ["92", "92"]
That's it. The tricky part was first to acknowledge that Regular Expressions work with strings, the second was that once I got the string I had to think about getting the number I wanted not as a number but as a string which was going to be surrounded by other characters and reaching out to those other characters, helped to find the solution.
Related
I'm working on this kata from Codewars. The task is:
Given a certain number, how many multiples of three could you obtain with its digits?
Supose that you have the number 362. The numbers that can be generated from it are:
362 ----> 3, 6, 2, 36, 63, 62, 26, 32, 23, 236, 263, 326, 362, 623, 632
I've written the following recursive function to calculate all possiblities:
const findMult_3 = (num) => {
const powerset = (set) => {
const combinations = []
const combine = (prefix, chars) => {
for (let i = 0; i < chars.length; i++) {
const newPrefix = parseInt(prefix + chars[i])
if (!combinations.includes(newPrefix)) {
combinations.push(newPrefix)
} else {
console.log('encountered duplicate')
}
combine(newPrefix, chars.filter((x, ind) => ind !== i))
}
}
combine('', set)
return combinations.sort((a, b) => a - b)
}
const allCombinations = powerset(num.toString().split(''))
const factorsOfThree = allCombinations.filter(x => x % 3 === 0).filter(x => x !== 0)
return [factorsOfThree.length, factorsOfThree.pop()]
}
findMult_3(43522283000229)
I noticed early on that I was encountered a lot of duplicate cases, hence the console.log('encountered duplicate') flag.
Execution of this algorithm is taking an extremely long time for large numbers, eg 43522283000229.
How can I improve the performance of this code, or should it be scrapped entirely?
With most coding katas, the choice of algorithm is far more important that implementation details, but before we get to that, let me point out the most glaring flaw of your implementation:
if (!combinations.includes(newPrefix)) {
combinations.push(newPrefix)
} else {
console.log('encountered duplicate')
}
combine(newPrefix, chars.filter((x, ind) => ind !== i))
combinations is an array, and includes works by iterating over the array and checking every element. That is, to check whether an element is a duplicate, you are comparing it with every previously encountered combination. Since there are exponentially many of those, this is going to be very slow. If you used a dictionary object or Map instead, your code would be far faster.
Also, did you notice you are proceeding with generating combination even if the combination is a duplicate? That's redundant.
So the cheap improvement would be:
const combinations = {};
if (combinations[prefix]) {
// duplicate, do nothing
} else {
combinations[prefix] = true;
combine(...);
}
The real improvement however is choosing a better algorithm. If you make use of the mathematical structure of the problem, you may be able to find the number of solutions without iterating over them all.
The following insights might help:
a number is divisible by three if and only if the sum of its digits is.
a sum of digits is divisible by 3 if and only if the sum of their remainders when divided by 3 is 0.
the order of digits in the input does not matter
One (first) optimization would be to only check or generate numbers where the sum of the digits is divisible by 3, since only those numbers are divisible by 3.
So in your example (362) you could skip all combinations with 3 and 2, 6 and 2 and all possible combinations with the 3 digits (because the sum of the 3 digits is not divisible by 3).
For the larger number (43522283000229) you can skip a lot more, for example all combinations with digits:
43, 35, 52, ...
435, 352, .., 283, ...
4352 (thus, including all possible combinations of those 4 digits), ...
43522, ...
43528, 43529, ...
43528309, ...
and so on
Possible algorithm:
Original number: 43522283000229
First, sort the digits: 00022222334589
Then find all distinct combinations of digits where
their sum is a multiple of 3:
left to right:
1 digit : 3, 9
2 digits: 03, 09, 24, 33, 39, 45, 48, ...
3 digits: 003, 009, 024, 033, 039, 222, 234, ...
n digits ...
Now, for all above numbers create every possible combination with their
digits, skip those with leading zeros.:
3, 9, 30, 90, 24, 42, 33, 39, 93, 45, 54, 48, 84, 300, 900,
204, 240, 402, 420, 309, 390, 903, 930, 222, 234, 243, ...
We don't have to check for division by 3, they all match.
We don't have to check for duplicates.
You could then sort the resulting list if needed.
Couldn't find any post with the right solution,
Basically what i'm trying to get, is to convert a string with special characters to KeyCode Array,
for Example: Convert "Hello#Today" to:
[104, 101, 108, 108, 111, 16, 50, 116, 111, 100, 97, 121]
Notice the "16, 50" which is combination of Shift(16) + 2(50),
In my current code i get (64) for # which is wrong:
[104, 101, 108, 108, 111, 64, 116, 111, 100, 97, 121]
my current function:
function convertToKeyCode(text) {
var results = text.split('')
.map(function (char) {
return char.charCodeAt(0);
});
return results;
}
Thanks
There is not a "ready-to-use" solution to convert a character to a key-code, at least in JavaScript.
Furthermore even if you implement your own conversion/mapping algorithm consider that different keyboard layouts generate characters with different key combinations.
Finally not every character code you may get with charCodeAt may have a corresponding key combination.
I am developing a SmartTV web app using JavaScript.
I want to write a regular expression which validate the local mobile operator codes:
op_codes = [33, 50, 63, 66, 67, 68, 73, 93, 95, 96, 97, 98, 99]
My code works as it should in Chrome and LG webOS. But in Samsung Tizen RegExp.test returns false even though it should be true.
Code sample:
var val = '0985739341',
op_codes = [33, 50, 63, 66, 67, 68, 73, 93, 95, 96, 97, 98, 99],
pattern = new RegExp('^0'+'('+op_codes.join('|')+')'+'\\d{7}$');
console.log(pattern.test(val)); //Samsung Tizen output: false
Here is the screenshot of Tizen console:
Tizen console(Updated)
I can't figure out what is wrong with my code, how can I solve it?
Same code executed on Chrome and Tizen:
Tizen(left) Chrome(right) console
Same variable Chrome and Tizen:
How it can be?
New Answer
Your latest screenshot (here) tells us that you have an invisible character in val. I really, really, really should have thought of that earlier. Apparently for whatever reason, whatever your source is for val, it's including an invisible character in it.
You'll need to identify it and, ideally, figure out where it comes from and fix it; otherwise, strip it out.
To figure out what it is, try this:
console.log("val", val);
Array.prototype.forEach.call(val, function(ch) {
console.log(ch.charCodeAt(0).toString(16));
});
If it were the value it seems to be, you'd get
val 0985739341
30 39 38 35 37 33 39 33 34 31
Live Copy:
var val = "0985739341";
console.log("val", val);
console.log(Array.prototype.map.call(val, function(ch) {
return ch.charCodeAt(0).toString(16);
}).join(" "));
...but I bet you get something else. It could be any of several invisible characters — a zero-width space (U+200B), a zero-width non-joiner (U+200C), etc. Here's an example with both of those:
var val = "0985\u200C\u200B739341";
console.log("val", val);
console.log(Array.prototype.map.call(val, function(ch) {
return ch.charCodeAt(0).toString(16);
}).join(" "));
Once you know what it is, you can find out where it comes from and get rid of it (or strip it from the string afterward).
Old, Probably-Incorrect Answer
I can't figure out what is wrong with my code...
If that screenshot is genuine, then there's nothing wrong with your code; there's a bug in the JavaScript engine being used on that device. This would appear to be one of the rare cases where the rule "select isn't broken" fails. (Would appear to be, keep being skeptical and keep double-checking yourself.)
You'll have to experiment to see where it fails (and file an appropriate bug report) and work around it. For instance, maybe the implementation of test incorrectly ignores capture groups and so isn't applying | correctly, or new RegExp is just fundamentally broken, or... It'll take a lot of experimentation to figure it out.
Below are your original validation (validate1) and three alternatives you might try. The second (validate2) uses a non-capturing group instead of a capturing group. They should be the same as far as test is concerned, but then again, your original code should work. :-)
var val = '0985739341';
var op_codes = [33, 50, 63, 66, 67, 68, 73, 93, 95, 96, 97, 98, 99];
var val1PatternStr = '^0'+'('+op_codes.join('|')+')'+'\\d{7}$';
var val1Pattern = new RegExp(val1PatternStr);
var val2PatternStr = '^0'+'(?:'+op_codes.join('|')+')'+'\\d{7}$';
var val2Pattern = new RegExp(val2PatternStr);
console.log(1, validate1(val));
console.log(2, validate2(val));
console.log(3, validate3(val));
console.log(4, validate4(val));
function validate1(val) {
return val1Pattern.test(val);
}
function validate2(val) {
return val2Pattern.test(val);
}
function validate3(val) {
return val.length === 10 &&
val[0] == "0" &&
op_codes.indexOf(+val.substring(1,3)) != -1 &&
/^\d+$/.test(val.substring(3));
}
function validate4(val) {
return val.length === 10 &&
val[0] == "0" &&
op_codes.indexOf(+val.substring(1,3)) != -1 &&
sillyIsDigit(val[3]) &&
sillyIsDigit(val[4]) &&
sillyIsDigit(val[5]) &&
sillyIsDigit(val[6]) &&
sillyIsDigit(val[7]) &&
sillyIsDigit(val[8]) &&
sillyIsDigit(val[9]);
}
function sillyIsDigit(ch) {
return ch >= "0" && ch <= "9";
}
If the JavaScript engine chokes on val[0], you'll have to change all of those [] on val to calls to charAt instead: val[0] => val.charAt(0).
I was wondering if it's possible to change the "Batman" text in the JavaScript Batman Joke to ASCII, then convert it and have it appear in the browser
The original joke is
javascript:Array(16).join("lol" - 1) + "Batman"
can this be changed to something like
javascript:Array(16).join("lol" - 1) + [66, 97, 116, 109, 097, 110].forEach(function(e) { document.write(String.fromCharCode(e)); } );
where [66, 97, etc] are the ASCII codes for Batman. This fails because the document object does not exist in an empty browser window.
(PS Feel free to delete if this isn't appropriate, it was only for fun)
You don't actually need to use any sort of loop or iterator for your array, String.fromCharCode will actually accept as many characters as you want to give it. So this will work just fine:
javascript:Array(16).join(-'.') + String.fromCharCode(66, 97, 116, 109, 097, 110);
However, if you wanted to call String.fromCharCode for every element of the array, you can. Every JavaScript function can be called using Function.prototype.apply which will run the function for each array element:
javascript:Array(16).join("lol" - 1) + String.fromCharCode.apply(this,[66, 97, 116, 109, 097, 110]);
Also, the purpose of "lol" - 1 is to try to create a bad number (a NaN or Not a Number). If you wanted to obfuscate things a bit further, you could use any math operation on a nonnumerical string. For example:
javascript:Array(16).join(-'.') + String.fromCharCode.apply(this,[66, 97, 116, 109, 097, 110])
because -'.' is interpenetrated as 0 - '.' which doesn't make any sense so it its NaN.
You can just do:
javascript:var str='';[66, 97, 116, 109, 097, 110].forEach(function(e) { str+= (String.fromCharCode(e)); } ); Array(16).join("lol" - 1) + str;
Or:
javascript:Array(16).join("lol" - 1) + [66, 97, 116, 109, 097, 110].map(function(e) { return (String.fromCharCode(e)); }).join('');
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
OK, check this one :
Visit this page here: http://efluo.net/
Open the JavaScript console
TEST 1:
Copy-paste this (and press enter) : window.DB["ar,i>í"]
It will show something like this :
Object {rootChange: "í", subjuntivo: Array[4], rootFind: "i", gerundio: "$ando", indicativo: Array[5]…}
TEST 2:
Now, copy-paste this one (It looks the exact same thing, well wait!) : window.DB["ar,i>í"]
And the response is :
undefined
OK, so could you please explain to me what's going on and how it is to be resolved (convert the second one, to the first one)?
Nothing weird about it, they're different characters that look the same. If you convert them to hex:
í = 69 cc 81
í = c3 ad
So, just replace one of them with the other.
Why would you be using characters like that in the first place?
That's because the length of the first string is 7, not 6. That last "character" of the first string is actually two characters that look like one. Try this:
var a = "ar,i>í", b = "ar,i>í";
for (var i = 0; i < a.length; ++i) {
console.log(a[i]);
}
for (var i = 0; i < b.length; ++i) {
console.log(b[i]);
}
If you look at the ASCII character encoding for both:
The first is:
[119, 105, 110, 100, 111, 119, 46, 68, 66, 91, 34, 97, 114, 44, 105, 62, 105, 769, 34, 93]
The second is:
[119, 105, 110, 100, 111, 119, 46, 68, 66, 91, 34, 97, 114, 44, 105, 62, 237, 34, 93]
So the second example is missing the part of the unicode character that corresponds to 769.
Check yourself using the code I used:
var arr = [];
for (var i = 0, l = s.length; i < l; i++) {
arr.push(s.charCodeAt(i));
}
console.log(arr);