Trouble with easy Coderbyte challenge counting x's and o's - javascript

I'm new to JavaScript and not sure why my code isn't working. I'm trying to return true if there are an equal amount of x's and o's, and return false if there are not. My code works for all inputs except "x" and "o". Any help is appreciated!
My code:
function ExOh(str) {
var x = str.match(/[^x$]/gi);
var o = str.match(/[^o$]/gi);
if (x.length == o.length) {
return true;
}
else {
return false;
}
}

Your regexps allow any characters other than x/y and $. You must have meant /x/gi and /o/gi.
function ExOh(str) {
var x = str.match(/x/gi) || "";
var o = str.match(/o/gi) || "";
if (x.length === o.length) {
return true;
}
else {
return false;
}
}
alert(ExOh("zzz"));
alert(ExOh("oozzzxx"));
Note that negated character classes like [^x] match all characters other than those inside the square brackets. $ inside them is treated as a literal dollar sign.
Typing a caret after the opening square bracket negates the character class. The result is that the character class matches any character that is not in the character class. Unlike the dot, negated character classes also match (invisible) line break characters. If you don't want a negated character class to match line breaks, you need to include the line break characters in the class. [^0-9\r\n] matches any character that is not a digit or a line break.

You need to set the value to something other than null if the str.match doesn't actually match something. You can't call length on null. Use the or operator to set the value to an empty string in your variable declaration.
function ExOh(str) {
var x = str.match(/[^x$]/gi) || '';
var o = str.match(/[^o$]/gi) || '';
if (x.length == o.length) {
return true;
}
else {
return false;
}
}
I hope this helps

Here's a solution for checking that the number of two characters is the same.
// How many 'x' characters occur in a string?
function numberOf(str, x) {
var matches = str.match(new RegExp(x, 'g'));
return matches ? matches.length : 0;
}
// Create a function to check if the number of x's and o's in
// a string are the same.
function same(x, o) {
return function(str) {
return numberOf(str, x) === numberOf(str, o);
};
}
var isSame = same('x', 'o');
isSame('xxooabc');

Remove ^ and $ from your regex , [^o$] match a single character not o or $. You just need to use /x/ and /o/ and flags ig, i for ignoring case and g for global match.
Typing a caret after the opening square bracket negates the character class. The result is that the character class matches any character that is not in the character class. Unlike the dot, negated character classes also match (invisible) line break characters. If you don't want a negated character class to match line breaks, you need to include the line break characters in the class. [^0-9\r\n] matches any character that is not a digit or a line break. ( Taken from http://www.regular-expressions.info/charclass.html )
Update : Add (!x && !o) and x && o in condition for avoiing error when zero matches are there. (!x && !o) for when both are not present.x && o will help only to check the condition x.length == o.length when both x and o are defined.
var div = document.getElementById('res');
function ExOh(str) {
var x = str.match(/x/gi);
var o = str.match(/o/gi);
if ((!x&&!o) || x && o && x.length == o.length) {
res.innerHTML = 'Same';
return true;
} else {
res.innerHTML = 'Not Same';
return false;
}
}
<input type=text oninput="ExOh(this.value)">
<div id=res></div>

Related

Turn lowercase letters of a string to uppercase and the inverse

let message = "heY, WHAt are you dOING?";
let count_changes = 0;
let isLetter = (letter) => {
if (('a'<=letter && letter >='z') || ('A'<=letter && letter >='Z')) {
return letter;
} else {
return -1;
}
}
for(let i = 0; i <= message.length; i++) {
if (isLetter(i) && message[i].toLowerCase()) {
message[i].toUpperCase();
count_changes++;
console.log(message[i].toLowerCase());
}
else if (isLetter(i) && message[i].toUpperCase()) {
message[i].toLowerCase();
count_changes++;
}
else {
console.error('Bad stirng');
}
}
Hello, I want to use the function isLetter to check the string message every character and when i use isLetter in the for loop to check in the if statement whether i is a Letter or not and also if its Lowercase letter later to when there is a change to Uppercase i increment count_changes++. Again with the second if statement if also i is Letter and in this case Uppercase letter then if change to lowercase letter to increment the count_changes++ so the count_changes to be my final result
thank you
By default, javascript's comparison of strings is case sensitive, therefore you can check a character's case by comparing it to either an upper or lower case converted value.
If it is the same, then the case is what you checked against, if not, the case is different.
"TRY" == "TrY" would return false, whereas "TRY" == "TRY" would return true;
So, use a variable to indicate the case of the last letter checked, then compare the next letter to the opposite case. If it matches, the case has changed, otherwise it is still the same case.
The isLetter function checks a value to be a single character, and using a regex test ensures that it is a letter - no punctuation or digits etc.
Your loop would always produce an error because you were iterating outside the lenth of the message string - arrays are 0 based.
let message = "heY, WHAt are you dOING?";
let count_changes = 0;
let lowerCase = message[0] == message[0].toLowerCase();
let messageLength = message.length;
function isLetter (val) {
// Check val is a letter of the alphabet a - z ignoring case.
return val.length == 1 && val.match(/[a-z]/i);
}
for (let i = 0; i < messageLength; i++) {
var char = message[i];
if (isLetter(char)) {
if(lowerCase) {
// Check to see if the next letter is upper case when the last one was lower case.
if(char == char.toUpperCase()) {
lowerCase = false;
count_changes++;
}
}
else {
// Check to see if the next letter is lower case when the last one was upper case.
if(char == char.toLowerCase()) {
lowerCase = true;
count_changes++;
}
}
}
else {
// Found a non-letter character.
console.error('Not a letter.');
}
}
console.log("Number of times the case changed: " + count_changes);
TL;DR:
let message = "heY, WHAt are you dOING?";
let newMessage = "";
let count_changes = 0;
let isLowerCaseLetter = (letter) => 'a' <= letter && letter <= 'z';
let isUpperCaseLetter = (letter) => 'A' <= letter && letter <= 'Z';
/* Iterate over every character of the message. */
for (let i = 0; i < message.length; i++) {
/* Cache the character at the current index. */
let character = message[i];
/* Check whether the character is a lowercase letter. */
if (isLowerCaseLetter(character)) {
newMessage += character.toUpperCase();
count_changes++;
}
/* Check whether the character is an uppercase letter. */
else if (isUpperCaseLetter(character)) {
newMessage += character.toLowerCase();
count_changes++;
}
/* Otherwise, just add the current character to the new message. */
else newMessage += character;
}
console.log("New Message: ", newMessage);
console.log("Changes: ", count_changes);
Your Mistakes:
The way you're checking if a character is a letter is wrong, due to >='z'. It should be <='z'. The same goes for the check against 'Z'.
Functions that have a Boolean connotation had better return true or false instead of -1 or the character itself as you do.
Inside isLetter you pass the index instead of the character itself. The function call should be isLetter(message[i]) instead of isLetter(i).
The very message you are testing will be deemed a 'bad string', because of the comma and the spaces between the words.
In your loop, the condition should be i < message.length, otherwise, every message will be deemed a 'bad string', because you'll exceed all characters and get an undefined value.
The methods toLowerCase and toUpperCase do not affect the original string but create a new one instead. If you want to assemble the resulting characters together, you have to initialise a newMessage string and concatenate it the processed character each loop.
Suggested solution:
Instead of one isLetter function create one checking if a character is a lowercase letter and one checking if it's an uppercase letter. That way you combine your checks and your if clause will be much simpler and more readable.
Ditch the isLetter check and the good string / bad string thing completely, so as not to have problems with in-between characters such as spaces and punctuation.
Attempt to minimise function calls, as for large strings, they will slow down your code a lot. In the code below, only 2 function calls per loop are used, compared to the accepted answer, which makes:
3 function calls per loop plus,
3 function calls when a character is letter (the majority of the time)
3 one-time function calls for from, map and join, which will matter for large strings.
Speedtest:
In a series of 5 tests using a massive string (2,825,856 chars long) the answers stack up as follows:
this answer (jsFiddle used):
[1141.91ms, 1150.93ms, 1093.75ms, 1048.50ms, 1183.03ms]
accepted answer (jsFiddle used):
[2211.30ms, 2985.22ms, 2136.73ms, 2279.26ms, 2482.34ms]
From what I understand, you want to count the number of characters in the string and return a string where all uppercase characters are replaced with lowercase characters and all lowercase characters are replaced with uppercase characters. Additionally, you want to increment countChanges once for every character changed.
This code should do what you want:
let message = "heY, WHAt are you dOING?";
let countChanges = 0;
let isLetter = c => c.toLowerCase() !== c.toUpperCase();
let isLowerCase = c => c.toLowerCase() === c;
let flippedMessage = Array.from(message).map((c)=>{
if(!isLetter(c)){
return c;
}
countChanges++;
// return uppercase character if c is a lowercase char
if(isLowerCase(c)){
return c.toUpperCase();
}
// Here, we know c is an uppercase character, so return the lowercase
return c.toLowerCase();
}).join('');
// flippedMessage is "HEy, whaT ARE YOU Doing?"
// countChanges is 18

javascript indexof regex A-Za-z0-9 always returns false

I have created a JS fiddle https://jsfiddle.net/95r110s9/#&togetherjs=Emdw6ORNpc
HTML
<input id="landlordstreetaddress2" class="landlordinputs" onfocusout="validateinputentries()" />
JS
validateinputentries(){
landlordstreetaddress2 = document.getElementById('landlordstreetaddress2').value;
goodcharacters = "/^[a-zA-Z0-9#.,;:'\s]+$/gi";
for (var i = 0; i < landlordstreetaddress2.length; i++){
if (goodcharacters.indexOf(landlordstreetaddress2.charAt(i)) != -1){
console.log('Character is valid');
}
}
}
Its pulling the value from an input and running an indexOf regex expression with A-Z a-z and 0-9 with a few additional characters as well.
The problem is that it works with the entry of BCDEFG...etc and 12345...etc, but when I type "A" or "Z" or "0" or "1", it returns incorrectly.
I need it to return the same with 0123456789, ABCDEF...XYZ and abcdef...xyz
I should point out that the below does work as intended:
var badcharacters = "*|,\":<>[]`\';#?=+/\\";
badcharacter = false;
//firstname
for (var i = 0; i < landlordfirstname.value.length; i++){
if (badcharacters.indexOf(landlordfirstname.value.charAt(i)) != -1){
badcharacter = true;
break;
}
if(landlordfirstname.value.charAt(0) == " "){
badcharacter = true;
break;
}
}
String.prototype.indexOf()
The indexOf() method returns the index within the calling String object of the first occurrence of the specified value, starting the search at fromIndex. Returns -1 if the value is not found.
So, you're trying to search this value "/^[a-zA-Z0-9#.,;:'\s]+$/gi" which "never" will be found in the entered string.
You actually want to test that regexp against the entered value.
/^[a-zA-Z0-9#.,;:'\s]+$/gi.test(landlordstreetaddress2)
function validateinputentries() {
var landlordstreetaddress2 = document.getElementById('landlordstreetaddress2').value;
if (/^[a-zA-Z0-9#.,;:'\s]+$/gi.test(landlordstreetaddress2)) {
console.log('Characters are valid');
} else {
console.log('Characters are invalid');
}
}
<input id="landlordstreetaddress2" class="landlordinputs" onfocusout="validateinputentries()" />
You're trying to combine two different methods of testing a string -- one way is with a regex; the other way is by checking each character against a list of allowed characters. What you've wound up with is checking each character against a list of what would have been a regex, if you hadn't declared it as a string.
Those methods conflict with each other; you need to pick one or the other.
Check each character:
This is closest to what you were attempting. You can't use character ranges here (like a-zA-Z) as you would in a regex; you have to spell out each allowed character individually:
var validateinputentries = function() {
var address = document.getElementById('landlordstreetaddress2').value;
var goodcharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#.,;:' ";
var badcharactersfound = false;
for (var i = 0; i < address.length; i++) {
if (goodcharacters.indexOf(address.charAt(i)) == -1) {
badcharactersfound = true;
console.log("not allowed: ", address.charAt(i));
}
}
if (badcharactersfound) {
// Show validation error here
}
}
<input id="landlordstreetaddress2" class="landlordinputs" onfocusout="validateinputentries()" />
Regular Expressions
The regex version is much simpler, because the regular expression is doing most of the work. You don't need to step through the string, just test the whole string against the regex and see what comes out. In this case you're looking to see if the input contains any characters that aren't allowed, so you want to use the character exception rule: [^abc] will match any character that is not a, b, or c. You don't want to anchor the match to the beginning or the end of the string, as you were doing with the initial ^ and the trailing $; and you can leave out the + because you don't care if there are sequential bad characters, you just care if they exist at all.
var validateinputentries = function() {
var address = document.getElementById('landlordstreetaddress2').value;
var regex = new RegExp("[^a-zA-Z0-9#.,;:'\\s]","g")
var badcharactersfound = address.match(regex);
// or the above two lines could also have been written like this:
// var bad = address.match(/[^a-zA-Z0-9#.,;:'\s]/g)
// In either case the "g" operator could be omitted; then it would only return the first bad character.
if (badcharactersfound) {
console.log("Not allowed: ", badcharactersfound);
}
}
<input id="landlordstreetaddress2" class="landlordinputs" onfocusout="validateinputentries()" />

How do i modify .replace to allow numbers, comma and dots [duplicate]

I have a string. I need to parse it, replacing any chars (except numbers (0 to 9),, and ..
How can I do it with javascript?
Tried with :
string.replace(/[a-zA-Z]*/, "");
but seems it doesnt works. Also, I need ANY chars, not only a-Z (also ?, /, white space, and so on, expect, as said, , and .
Use a negated character class
[^0-9,.]
and put in any character you don't want to be replaced, it will match all the others.
See it here on Regexr
You can optimize it by adding a quantifier +, so that it replaces a sequence of those characters at once and not each by each.
string.replace(/[^0-9,.]+/g, "");
As Felix Kling pointed out, its important to use the global option g to match on all occurrences of the pattern.
See it here on Regexr
string.replace(/[^\d,.]+/g, "");
should do.
[^\d.,] means "any character except digit, comma or period", a negated character class.
Use + instead of * or you'll have lots of empty matches replaced with empty strings.
Use /g so all instances are replaced.
Try to replace all chars except digits and . , and do the replace globally:
string.replace(/[^0-9\,\.]+/g, "");
Try This
Below code is prevent alpha key
onKeypress="return Custom(event,'[0-9]');"
function Custom(e, cPattern) {
var key = [e.keyCode || e.which];
var pattern = new String(cPattern);
var keychar = String.fromCharCode([e.keyCode || e.which]);
var pattern1 = new RegExp(pattern);
if ((key == null) || (key == 0) || (key == 8) ||
(key == 9) || (key == 13) || (key == 27)) {
return true;
}
else if (pattern1.test(keychar)) {
return true;
}
else {
e.preventDefault ? e.preventDefault() : e.returnValue = false;
}
}

Unclosed group near index 1

Somebody can help me with this function on javascript?
i did this function above on javascript, but when i try to use on this string: Item 1 – 1 X 500 OS 129062.
MATERIAL DE NOSSA PROPRIEDADE QUE SEGUE P/ ANALISE E TESTE, SEM DÉBITO
(AMOSTRA GRÁTIS).
I get a error: Unclosed group near index 1
Plz, help me
function retiraAcentos(texto) {
var caracEspec = '.áàãâäéèêëíìîïóòõôöúùûüçñÁÀÃÂÄÉÈÊËÍÌÎÏÓÒÕÖÔÚÙÛÜÇÑ/';
var caracComum = '.aaaaaeeeeiiiiooooouuuucnAAAAAEEEEIIIIOOOOOUUUUCN.';
var textoResultado = '';
for (i = 0; i < texto.length; i++) {
var letra = texto.substr(i, 1);
if ((letra == "*") || (letra == "?") || (letra == "\n") || (letra == '+')) {
continue;
}
var posLetra = caracEspec.search(letra);
if (posLetra >= 0) {
textoResultado += caracComum.substr(posLetra, 1);
} else {
textoResultado += letra;
}
}
return textoResultado;
}
The search function expects a regular expression. Try using indexOf instead:
var posLetra = caracEspec.indexOf(letra);
I made some research using jsfiddle.
It turns out that if a text contains a parenthesis (opening or closing),
then such a parenthesis at some point becomes the argument of search
function and it raises unterminated parenthetical error.
Apparently this function uses regex internally and a single parenthesis
is not any valid regex.
Use indexOf instead of search.
Another correction: Remove dot char from the beginning of caracEspec
and caracComum.
If you used search then the dot (treated as regex) matched any char,
in this case the first char from caracEspec, giving posLetra = 0.
This resulted in taking the 1st char from caracComum (fortunately, also a dot).
Now these combinations are not needed.

Javascript validate string is a character followed by numbers

I am trying to validate a string where the first character must be an 'x' and the remaining characters must be numerical. For example:
x1234 == true;
k1234 == false;
x12k4 == false;
1x123 == false;
Here is my code:
function isValidCode(code){
var firstLetter = code.substring(0,1);
var remainingCode = code.substring(1);
var validCode = false;
// Debugging
console.log(firstLetter);
console.log(remainingCode);
if(firstLetter == 'x'){
validCode = true;
}
if(isNumeric(Number(remainingCode))){
validCode = true;
}
}
I've debugged my isNumeric() function, so I'm 99.9% sure the issue isn't there, but here it is just in case:
function isNumeric(numberIn)
{
var returnValue = true;
if (isNaN(numberIn) || isNaN(parseInt(numberIn, 10)))
{
returnValue = false;
}
return returnValue;
}
I've tried several things such as reversing my logic where I start with the given condidtion being true and then checking if(!(firstLetter == 'x')) I've tried == and ===and I've tried casting the remaining portion of the code with Number() , +() and not casting it at all, but none of these seeem to do the trick. The console does log the proper first character and remaining characters in the code so I'm not sure what is wrong.
You can use a regular expression test:
function isValidCode(code) {
return /^[a-z]\d+$/.test(code);
}
I am making an assumption that a lower case letter is required, followed by at least one digit.
To match only only the letter 'x', use:
function isValidCode(code) {
return /^x\d+$/.test(code);
}
You can use RegExp /^x(?=\d+$)/ to match x at beginning of input followed by digits followed by end of input
var arr = ["x1234"
, "k1234"
, "x12k4"
, "1x123"];
var re = /^x(?=\d+$)/;
arr.forEach(function(str) {
console.log(`${str}: ${re.test(str)}`)
})

Categories