Map and RegEx weirdness [duplicate] - javascript

This question already has answers here:
Why does a RegExp with global flag give wrong results?
(7 answers)
Closed 5 years ago.
I'm doing a kata that decodes a caesar cipher string into readable text. I'm using RegEx within a map to find special characters and skip over them, but the output is flaky if I have two or more special characters next to each other ', ' or ' :) '. It seems to skip over some special characters.
Can anyone explain what's going on?
I haven't included the changeCharCode function code because I think the issue is in my map.
function decodeString(string) {
const stringArr = string.toLowerCase().split('');
const specialCharacters = /[ .,\/#!$%\^&\*;:{}=\-_`~()]/g;
const codeOfX = 'x'.charCodeAt(0);
const codeOfLastLetter = stringArr[stringArr.length - 1].charCodeAt(0);
const codeShift = codeOfX - codeOfLastLetter;
return stringArr.map((elem) => {
// Special character treatment
return specialCharacters.test(elem) === true ? elem : changecharCode(elem, codeShift);
}).join('').toUpperCase();
}
function changecharCode (letter, codeShift) {
const currentCode = letter.charCodeAt(0);
// Uppercase letters
if ((currentCode >= 65) && (currentCode <= 90))
return letter = String.fromCharCode(((currentCode - 65 + codeShift) % 26) + 65);
// Lowercase letters
else if ((currentCode >= 97) && (currentCode <= 122))
return letter = String.fromCharCode(((currentCode - 97 + codeShift) % 26) + 97);
}
decodeString(' :) ') => ' ) '
decodeString(', ') => ','

Remove the global flag at the end of regex, you have to proceed one character at a time:
function decodeString(string) {
const stringArr = string.toLowerCase().split('');
const specialCharacters = /[ .,\/#!$%\^&\*;:{}=\-_`~()]/;
// here ___^
const codeOfX = 'x'.charCodeAt(0);
const codeOfLastLetter = stringArr[stringArr.length - 1].charCodeAt(0);
const codeShift = codeOfX - codeOfLastLetter;
return stringArr.map((elem) => {
// Special character treatment
return specialCharacters.test(elem) === true ? elem : changecharCode(elem, codeShift);
}).join('').toUpperCase();
}
function changecharCode (letter, codeShift) {
const currentCode = letter.charCodeAt(0);
// Uppercase letters
if ((currentCode >= 65) && (currentCode <= 90))
return letter = String.fromCharCode(((currentCode - 65 + codeShift) % 26) + 65);
// Lowercase letters
else if ((currentCode >= 97) && (currentCode <= 122))
return letter = String.fromCharCode(((currentCode - 97 + codeShift) % 26) + 97);
}
console.log('>'+decodeString(' :) ')+'<');
console.log('>'+decodeString(', ')+'<');

It's the same issue as why-does-my-javascript-regex-test-give-alternating-results. Let's say that the problem was occurred because of g flag which keeps a global state of matching. The solution in your case is supposed to be removing a g flag, once your function proceeds characters one by one, then the g flag is unnecessary.

The problem is in your changecharCode function: if a character code is not within the two ranges that are tested, then the function returns nothing, i.e. undefined. The join you do later on will produce an empty string for each undefined value, so you don't see anything for that in the output.
If you would add a final to changecharCode:
return ' '; // or whatever character you want here
Then the output will have the same number of characters as the input.

Related

how to check first letter of every word in the string and returns next letter in the alphabet [duplicate]

I am build an autocomplete that searches off of a CouchDB View.
I need to be able to take the final character of the input string, and replace the last character with the next letter of the english alphabet. (No need for i18n here)
For Example:
Input String = "b"
startkey = "b"
endkey = "c"
OR
Input String = "foo"
startkey = "foo"
endkey = "fop"
(in case you're wondering, I'm making sure to include the option inclusive_end=false so that this extra character doesn't taint my resultset)
The Question
Is there a function natively in Javascript that can just get the next letter of the alphabet?
Or will I just need to suck it up and do my own fancy function with a base string like "abc...xyz" and indexOf()?
my_string.substring(0, my_string.length - 1)
+ String.fromCharCode(my_string.charCodeAt(my_string.length - 1) + 1)
// This will return A for Z and a for z.
function nextLetter(s){
return s.replace(/([a-zA-Z])[^a-zA-Z]*$/, function(a){
var c= a.charCodeAt(0);
switch(c){
case 90: return 'A';
case 122: return 'a';
default: return String.fromCharCode(++c);
}
});
}
A more comprehensive solution, which gets the next letter according to how MS Excel numbers it's columns... A B C ... Y Z AA AB ... AZ BA ... ZZ AAA
This works with small letters, but you can easily extend it for caps too.
getNextKey = function(key) {
if (key === 'Z' || key === 'z') {
return String.fromCharCode(key.charCodeAt() - 25) + String.fromCharCode(key.charCodeAt() - 25); // AA or aa
} else {
var lastChar = key.slice(-1);
var sub = key.slice(0, -1);
if (lastChar === 'Z' || lastChar === 'z') {
// If a string of length > 1 ends in Z/z,
// increment the string (excluding the last Z/z) recursively,
// and append A/a (depending on casing) to it
return getNextKey(sub) + String.fromCharCode(lastChar.charCodeAt() - 25);
} else {
// (take till last char) append with (increment last char)
return sub + String.fromCharCode(lastChar.charCodeAt() + 1);
}
}
return key;
};
Here is a function that does the same thing (except for upper case only, but that's easy to change) but uses slice only once and is iterative rather than recursive. In a quick benchmark, it's about 4 times faster (which is only relevant if you make really heavy use of it!).
function nextString(str) {
if (! str)
return 'A' // return 'A' if str is empty or null
let tail = ''
let i = str.length -1
let char = str[i]
// find the index of the first character from the right that is not a 'Z'
while (char === 'Z' && i > 0) {
i--
char = str[i]
tail = 'A' + tail // tail contains a string of 'A'
}
if (char === 'Z') // the string was made only of 'Z'
return 'AA' + tail
// increment the character that was not a 'Z'
return str.slice(0, i) + String.fromCharCode(char.charCodeAt(0) + 1) + tail
}
Just to explain the main part of the code that Bipul Yadav wrote (can't comment yet due to lack of reps). Without considering the loop, and just taking the char "a" as an example:
"a".charCodeAt(0) = 97...hence "a".charCodeAt(0) + 1 = 98 and String.fromCharCode(98) = "b"...so the following function for any letter will return the next letter in the alphabet:
function nextLetterInAlphabet(letter) {
if (letter == "z") {
return "a";
} else if (letter == "Z") {
return "A";
} else {
return String.fromCharCode(letter.charCodeAt(0) + 1);
}
}
var input = "Hello";
var result = ""
for(var i=0;i<input.length;i++)
{
var curr = String.fromCharCode(input.charCodeAt(i)+1);
result = result +curr;
}
console.log(result);
I understand the original question was about moving the last letter of the string forward to the next letter. But I came to this question more interested personally in changing all the letters in the string, then being able to undo that. So I took the code written by Bipul Yadav and I added some more code. The below code takes a series of letters, increments each of them to the next letter maintaining case (and enables Zz to become Aa), then rolls them back to the previous letter (and allows Aa to go back to Zz).
var inputValue = "AaZzHello";
console.log( "starting value=[" + inputValue + "]" );
var resultFromIncrementing = ""
for( var i = 0; i < inputValue.length; i++ ) {
var curr = String.fromCharCode( inputValue.charCodeAt(i) + 1 );
if( curr == "[" ) curr = "A";
if( curr == "{" ) curr = "a";
resultFromIncrementing = resultFromIncrementing + curr;
}
console.log( "resultFromIncrementing=[" + resultFromIncrementing + "]" );
inputValue = resultFromIncrementing;
var resultFromDecrementing = "";
for( var i2 = 0; i2 < inputValue.length; i2++ ) {
var curr2 = String.fromCharCode( inputValue.charCodeAt(i2) - 1 );
if( curr2 == "#" ) curr2 = "Z";
if( curr2 == "`" ) curr2 = "z";
resultFromDecrementing = resultFromDecrementing + curr2;
}
console.log( "resultFromDecrementing=[" + resultFromDecrementing + "]" );
The output of this is:
starting value=[AaZzHello]
resultFromIncrementing=[BbAaIfmmp]
resultFromDecrementing=[AaZzHello]

Else if statements with toUpperCase(), toLowerCase() and Number.isInteger() [duplicate]

How can I test if a letter in a string is uppercase or lowercase using JavaScript?
The answer by josh and maleki will return true on both upper and lower case if the character or the whole string is numeric. making the result a false result.
example using josh
var character = '5';
if (character == character.toUpperCase()) {
alert ('upper case true');
}
if (character == character.toLowerCase()){
alert ('lower case true');
}
another way is to test it first if it is numeric, else test it if upper or lower case
example
var strings = 'this iS a TeSt 523 Now!';
var i=0;
var character='';
while (i <= strings.length){
character = strings.charAt(i);
if (!isNaN(character * 1)){
alert('character is numeric');
}else{
if (character == character.toUpperCase()) {
alert ('upper case true');
}
if (character == character.toLowerCase()){
alert ('lower case true');
}
}
i++;
}
if (character == character.toLowerCase())
{
// The character is lowercase
}
else
{
// The character is uppercase
}
The problem with the other answers is, that some characters like numbers or punctuation also return true when checked for lowercase/uppercase.
I found this to work very well for it:
function isLowerCase(str)
{
return str == str.toLowerCase() && str != str.toUpperCase();
}
This will work for punctuation, numbers and letters:
assert(isLowerCase("a"))
assert(!isLowerCase("Ü"))
assert(!isLowerCase("4"))
assert(!isLowerCase("_"))
To check one letter just call it using isLowerCase(str[charIndex])
const isUpperCase = (string) => /^[A-Z]*$/.test(string)
then :
isUpperCase('A') // true
isUpperCase('a') // false
This will log true if character is uppercase letter, and log false in every other case:
var letters = ['a', 'b', 'c', 'A', 'B', 'C', '(', ')', '+', '-', '~', '*'];
​​​for (var ​i = 0; i<letters.length; i++) {
if (letters[i] === letters[i].toUpperCase()
&& letters[i] !== letters[i].toLowerCase()) {
console.log(letters[i] + ": " + true);
} else {
console.log(letters[i] + ": " + false);
}
}​
You may test it here: http://jsfiddle.net/Axfxz/ (use Firebug or sth).
​​​for (var ​i = 0; i<letters.length; i++) {
if (letters[i] !== letters[i].toUpperCase()
&& letters[i] === letters[i].toLowerCase()) {
console.log(letters[i] + ": " + true);
} else {
console.log(letters[i] + ": " + false);
}
}​
and this is for lowercase:).
function isUpperCase(myString) {
return (myString == myString.toUpperCase());
}
function isLowerCase(myString) {
return (myString == myString.toLowerCase());
}
You could utilize a regular expression test and the toUpperCase method:
String.prototype.charAtIsUpper = function (atpos){
var chr = this.charAt(atpos);
return /[A-Z]|[\u0080-\u024F]/.test(chr) && chr === chr.toUpperCase();
};
// usage (note: character position is zero based)
'hi There'.charAtIsUpper(3); //=> true
'BLUE CURAÇAO'.charAtIsUpper(9); //=> true
'Hello, World!'.charAtIsUpper(5); //=> false
See also
function isCapital(ch){
return ch.charCodeAt() >= 65 && ch.charCodeAt() <= 90;
}
More specifically to what is being asked. Pass in a String and a position to check. Very close to Josh's except that this one will compare a larger string. Would have added as a comment but I don't have that ability yet.
function isUpperCase(myString, pos) {
return (myString.charAt(pos) == myString.charAt(pos).toUpperCase());
}
function isLowerCase(myString, pos) {
return (myString.charAt(pos) == myString.charAt(pos).toLowerCase());
}
A good answer to this question should be succinct, handle unicode correctly, and deal with empty strings and nulls.
function isUpperCase(c) {
return !!c && c != c.toLocaleLowerCase();
}
This approach deals with empty strings and nulls first, then ensures that converting the given string to lower case changes its equality. This ensures that the string contains at least one capital letter according to the current local's capitalisation rules (and won't return false positives for numbers and other glyphs that don't have capitalisation).
The original question asked specifically about testing the first character. In order to keep your code simple and clear I'd split the first character off the string separately from testing whether it's upper case.
You can also use a regular expression to explicitly detect uppercase roman alphabetical characters.
isUpperCase = function(char) {
return !!/[A-Z]/.exec(char[0]);
};
EDIT: the above function is correct for ASCII/Basic Latin Unicode, which is probably all you'll ever care about. The following version also support Latin-1 Supplement and Greek and Coptic Unicode blocks... In case you needed that for some reason.
isUpperCase = function(char) {
return !!/[A-ZÀ-ÖØ-ÞΆΈ-ΏΑ-ΫϢϤϦϨϪϬϮϴϷϹϺϽ-Ͽ]/.exec(char[0]);
};
This strategy starts to fall down if you need further support (is Ѭ uppercase?) since some blocks intermix upper and lowercase characters.
There's a really simple answer, which nobody else has mentioned:
function isLowerCase(str) {
return str !== str.toUpperCase();
}
If str.toUpperCase() does not return the same str, it has to be lower case. To test for upper case you change it to str !== str.toLowererCase().
Unlike some other answers, it works correctly on non-alpha characters (returns false) and it works for other alphabets, accented characters etc.
This is straightforward, readable solution using a simple regex.
// Get specific char in string
const char = string.charAt(index);
const isLowerCaseLetter = (/[a-z]/.test(char));
const isUpperCaseLetter = (/[A-Z]/.test(char));
I believe this is the easiest solution.. You can use onchange handler in input field .. to do the validation
const isValid = e.target.value === e.target.value.toLowerCase()
if (isValid) {
//Do something
} else {
//Do something
}
With modern browsers you can use regexp and unicode property tests e.g.
/\p{Lu}/u.test("A") // is true
/\p{Lu}/u.test("Å") // is true
/\p{Lu}/u.test("a1å") // is false
More info here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes
List of general categories here:
https://unicode.org/reports/tr18/#General_Category_Property
You can also use this, it will check the string for lower and uppercase
var s = "a"
if(/[a-z]/.test(s)){
alert ('lower case true');
}
if(/[A-Z]/.test(s)) {
alert ('upper case true');
}
The best way is to use a regular expression, a ternary operator, and the built in .test() method for strings.
I leave you to Google the ins and outs of regular expressions and the test method for strings (they're easy to find), but here we'll use it to test your variable.
/[a-z]/i.test(your-character-here)
This will return TRUE of FALSE based on whether or not your character matches the character set in the regular expression. Our regular expression checks for all letters a-z /[a-z]/ regardless of their case thanks to the i flag.
So, a basic test would be:
var theAnswer = "";
if (/[a-z]/i.test(your-character-here)) {
theAnswer = "It's a letter."
}
Now we need to determine if it's upper or lower case. So, if we remove the i flag from our regular expression, then our code above will test for lower case letters a-z. And if we stick another if statement in the else of our first if statement, we can test for upper case too by using A-Z. Like this:
var theAnswer = "";
if (/[a-z]/.test(your-character-here)) {
theAnswer = "It's a lower case letter."
} else if (/[A-Z]/.test(your-character-here)) {
theAnswer = "It's an upper case letter.";
}
And just in case it's not a letter, we can add a final else statement:
var theAnswer = "";
if (/[a-z]/.test(your-character-here)) {
theAnswer = "It's a lower case letter."
} else if (/[A-Z]/.test(your-character-here)) {
theAnswer = "It's an upper case letter.";
} else {
theAnswer = "It's not a letter."
}
The above code would work. But it's kinda ugly. Instead, we can use a "ternary operator" to replace our if-else statements above. Ternary operators are just shorthand simple ways of coding an if-else. The syntax is easy:
(statement-to-be-evaluated) ? (code-if-true) : (code-if-false)
And these can be nested within each other, too. So a function might look like:
var theAnswer = "";
function whichCase(theLetter) {
theAnswer = /[a-z]/.test(theLetter) ? "It's lower case." : "";
theAnswer = /[A-Z]/.test(theLetter) ? "It's upper case." : "";
return(theAnswer);
}
The above code looks good, but won't quite work, because if our character is lower case, theAnswer gets set to "" when it test for uppercase, so lets nest them:
var theAnswer = "";
function whichCase(theLetter) {
theAnswer = /[a-z]/.test(theLetter) ? "It's lower case." : (/[A-Z]/.test(theLetter) ? "It's upper case." : "It's not a letter.");
return(theAnswer);
}
That will work great! But there's no need to have two seperate lines for setting the variable theAnswer and then returning it. And we should be using let and const rather than var (look those up if you're not sure why). Once we make those changes:
function whichCase(theLetter) {
return(/[A-Z]/.test(theLetter) ? "It's upper case." : (/[a-z]/.test(theLetter) ? "It's lower case." : "It's not a letter."));
}
And we end up with an elegant, concise piece of code. ;)
See my comment on the chosen answer. Other solutions that limit to the ASCII table or use the actual character literals completely ignore Unicode and the several hundred other characters there that have case.
This code will set the caseGroup variable to:
1 for Upper Case
-1 for Lower Case
0 for Without Case
var caseGroup = (character.toLowerCase() == character.toUpperCase() ? 0 : (character == character.toUpperCase() ? 1 : -1));
You could bake that into something like this...
function determineCase(character) {
return (character.toLowerCase() == character.toUpperCase() ? 0 : (character == character.toUpperCase() ? 1 : -1));
}
function isUpper(character) {
return determineCase(character) == 1;
}
function isLower(character) {
return determineCase(character) == -1;
}
function hasCase(character) {
return determineCase(character) != 0;
}
function solution(s) {
var c = s[0];
if (c == c.toUpperCase() && !(c >= '0' && c <= '9') &&(c >='A' && c <= 'Z')) {
return 'upper';
} else if (c == c.toLowerCase() && !(c >= '0' && c <= '9') &&(c >='a' && c <= 'z')){
return 'lower';
} else if (c >= '0' && c <= '9'){
return 'digit'
} else {
return 'other'
}
}
var str1= (solution('A')) // upper
var str2 = solution('b') // lower
var str3 = solution('1') // digit
var str4 = solution('_') // other
console.log(`${str1} ${str2} ${str3} ${str4}`)
You can test if your array has an upper case or lower case string by using the match method and regex, below is just a basic foundation to start your test
var array = ['a', 'b', 'c', 'A', 'B', 'C', '(', ')', '+', '-', '~', '*'];
var character = array.join('')
console.log(character)
var test = function(search){
upperCase = search.match(/[A-Z]/g)
console.log(upperCase)
lowerCase = search.match(/[a-z]/g)
console.log(lowerCase)
}
test(character)
This is how I did it recently:
1) Check that a char/string s is lowercase
s.toLowerCase() == s && s.toUpperCase() != s
2) Check s is uppercase
s.toUpperCase() == s && s.toLowerCase() != s
Covers cases where s contains non-alphabetic chars and diacritics.
function checkCharType (charToCheck) {
// body...
var returnValue = "O";
var charCode = charToCheck.charCodeAt(0);
if(charCode >= "A".charCodeAt(0) && charCode <= "Z".charCodeAt(0)){
returnValue = "U";
}else if (charCode >= "a".charCodeAt(0) &&
charCode <= "z".charCodeAt(0) ){
returnValue = "L";
}else if (charCode >= "0".charCodeAt(0) &&
charCode <= "9".charCodeAt(0) ) {
returnValue = "N";
}
return returnValue;
}
var myString = prompt("Enter Some text: ", "Hello world !");
switch (checkCharType(myString)) {
case "U":
// statements_1
document.write("First character was upper case");
break;
case "L":
document.write("First character was a lower case");
break;
case "N":
document.write("First character was a number");
break
default:
// statements_def
document.write("First character was not a character or a number");
break;
}
Define a Function checkCharType().By declaring the variable returnValue and initialising it to the Character "O" to indicate it's Some other value.
U for uppercase; L for Lowercase ; N for number
Use the charCodeAt() method to get the character code of the first character.
Using if Statement , which check within what range of values the character code falls.
If it falls between the character codes for A and Z, Its Uppercase,
character code between a and z ,Its Lowercase. and so on.
"A".charCode(0)
var myChar = new String("A");
myChar.charCodeAt(0);
"A" : number code "65“
Check the String
This checks the ENTIRE string, not just the first letter. I thought I'd share it with everyone here.
Here is a function that uses a regular expression to test against the letters of a string; it returns true if the letter is uppercase (A-Z). We then reduce the true/false array to a single value. If it is equal to the length of the string, that means all the letters passed the regex test, which means the string is uppercase. If not, the string is lowercase.
const isUpperCase = (str) => {
let result = str
.split('')
.map(letter => /[A-Z]/.test(letter))
.reduce((a, b) => a + b);
return result === str.length;
}
console.log(isUpperCase('123')); // false
console.log('123' === '123'.toUpperCase()); // true
This question has clearly been answered a number of times, but i thought i'd share my solution as I haven't seen it in the given answers.
var lower_case = function(letter){
lowers = "abcdefghijklmnopqrstuvwxyz";
return letter === letter.toLowerCase() && lowers.indexOf(letter) >= 0
};
var upper_case = function(letter){
uppers = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
return letter === letter.toUpperCase() && uppers.indexOf(letter) >= 0
};
2¢
function checkCase(c){
var u = c.toUpperCase();
return (c.toLowerCase() === u ? -1 : (c === u ? 1 : 0));
};
Based on Sonic Beard comment to the main answer. I changed the logic in the result:
0: Lowercase
1: Uppercase
-1: neither
Assuming that a string is only considered to not be all uppercase if at least one lowercase letter is present, this works fine. I understand it's not concise and succinct like everybody else tried to do, but does it works =)
function isUpperCase(str) {
for (var i = 0, len = str.length; i < len; i++) {
var letter = str.charAt(i);
var keyCode = letter.charCodeAt(i);
if (keyCode > 96 && keyCode < 123) {
return false;
}
}
return true;
}
I need to test against a string of any character (including white space, marks, numbers, unicode characters...). Because white space, numbers, marks... will be the same in both upper case and lower case, and I want to find real upper case letters, I do this:
let countUpperCase = 0;
let i = 0;
while (i <= string.length) {
const character = string.charAt(i);
if (character === character.toUpperCase() && character !== character.toLowerCase()) {
countUpperCase++;
}
i++;
}
Simply check the ASCII value
// IsLower verify that a string does not contains upper char
func IsLower(str string) bool {
for i := range str {
ascii := int(str[i])
if ascii < 91 && ascii > 64 {
return false
}
}
return true
}
Another way is to compare the character with an empty object, i don't really know's why it works, but it works :
for (let i = 1; i <= 26; i++) {
const letter = (i + 9).toString(36).toUpperCase();
console.log('letter', letter, 'is upper', letter<{}); // returns true
}
for (let i = 1; i <= 26; i++) {
const letter = (i + 9).toString(36);
console.log('letter', letter, 'is upper', letter<{}); // returns false
}
so in a function :
function charIsUpper(character) {
return character<{};
}
EDIT: it doesn't work with accents and diacritics, so it's possible to remove it
function charIsUpper(character) {
return character
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')<{};
}
One I use (notice this doesnt make "TestString" as "T est String" or " Test String").
function seperateCapitalised(capitalisedString) {
if (typeof capitalisedString !== "string" || capitalisedString.length === 0)
return capitalisedString;
var newStr = capitalisedString[0];
for (var i = 1; i < capitalisedString.length; i++) {
var char = capitalisedString[i];
if (char === char.toUpperCase() && isNaN(char)) {
newStr += ' ' + char;
}
else {
newStr += char;
}
}
return newStr;
}

Alpha numeric sequence generation using javascript

I need to generate the custom sequence as below using javascript based on input. For ex: if i provide the input isAA1 then output should be AA2 and if provided input as AA9 then the output should be AB0. I can do with the if else by creating the token's but it looks like we need to keep so many if else condition's. Wanted to know the more efficient way to handle this.
AA0
AA1
AA2
AA3
AA4
AA5
AA6
AA7
AA8
AA9
AB0
AB1
AB2
AB3
AB4
AB5
AB6
AB7
AB8
AB9
AC0
AC1
.
.
.
ZZ9
Using reduceRight() you can iterate over the spread string in reverse, incrementing each character as necessary using the character's charCodeAt() value adjusted by its offset from 0, and cycling it based on its remainder (%) for the appropriate cycle length (10 for integers, 26 for letters). The accumulator tracks whether to sum on the next iteration, as well as the result string.
const incrementAlphaNumeric = (str) => {
let iter, min, len;
return [...str]
.reduceRight((a, c, i) => {
let code = c.charCodeAt();
if (code >= 48 && code <= 57) { // [0-9]
min = 48;
len = 10;
} else if ((code >= 65 && code <= 90)) { // [A-Z]
min = 65;
len = 26;
}
iter = code - min + a.sum;
a.res[i] = String.fromCharCode(iter % len + min);
a.sum = Math.floor(iter / len);
return a;
}, { res: [], sum: 1 })
.res
.join('');
}
console.log(incrementAlphaNumeric('AA0')); // AA1
console.log(incrementAlphaNumeric('AA9')); // AB0
console.log(incrementAlphaNumeric('AZ9')); // BA0
console.log(incrementAlphaNumeric('ZZ9')); // AA0
I had a little time on my hands, and this seemed like a fun challenge, so I went ahead and built a function that accepts any string of uppercase letters and/or numbers. I realize it might be a little bit overkill for the requirements of the question, but it does satisfy all of the requirements, and someone else stumbling across this question in the future might find this helpful.
It works by converting the right-most character to its respective character code, incrementing it by 1, and checking if the resulting character code is outside of the A-Z or 0-9 range. If it is outside of its range, we reset it to its "base value" (A or 0) and set a carry flag (this is very similar to how binary adder circuits work). If the carry flag is set, we recursively call the function using the next-to-last character as our new "right-most" character until we no longer need to carry. At which point, we simply return the new string.
increment('AA0') > 'AA1
increment('AA9') > 'AB0
increment('ZZ9') > 'AA0
increment('AZ9BE') > 'AZ9BF
const A = 65
const Z = 90
const ZERO = 48
const NINE = 57
const isDigit = (char) => char >= 48 && char <= 57
const incDigit = (char) => char + 1 > NINE ? ZERO : char + 1
const incLetter = (char) => char + 1 > Z ? A : char + 1
const codeToChar = (code) => String.fromCharCode(code)
const setChar = (index, char, str) => {
const charArr = [...str]
charArr.splice(index, 1, char)
return charArr.join('')
}
const increment = (str, place = str.length - 1) => {
if (place < 0) return str;
const char = str.charCodeAt(place)
const nextChar = isDigit(char) ? incDigit(char) : incLetter(char)
const carry = nextChar - char !== 1;
str = setChar(place, codeToChar(nextChar), str)
if (carry)
return increment(str, --place)
else return str
}
let demoStr = 'AA0'
setInterval(() => {
demoStr = increment(demoStr)
console.log(demoStr)
}, 25)
You could use this next() function, which increments the letters of the input string by converting them to base 26 numeric strings and back whenever an overflow is detected from incrementing the decimal portion of the input string:
const next = (() => {
const charCodeA = 'A'.charCodeAt(0);
const to = (replacer, string) => string.replace(/./g, replacer);
const padStart = (string, { length }, pad) => string.padStart(length, pad);
const truncate = (string, { length }) => string.slice(-length);
const letter = (base26String) => String.fromCharCode(
parseInt(base26String, 26) + charCodeA
);
const base26 = (letterString) => (
letterString.charCodeAt(0) - charCodeA
).toString(26);
const increment = (numbersString, radix) => (
parseInt(numbersString, radix) + 1
).toString(radix);
return (prev) => {
const [, prevL, prevD] = prev.match(/^([A-Z]+)([0-9]+)$/);
const nextD = padStart(increment(prevD, 10), prevD, '0');
const carry = nextD.length > prevD.length;
const nextL = carry
? padStart(to(letter, increment(to(base26, prevL), 26)), prevL, 'A')
: prevL;
return truncate(nextL, prevL) + truncate(nextD, prevD);
};
})();
console.log(next('AA0')); // AA1
console.log(next('AZ9')); // BA0
console.log(next('ZZ9')); // AA0
console.log(next('AAA00')); // AAA01
console.log(next('AZZ09')); // AZZ10
console.log(next('AZZ99')); // BAA00
console.log(next('ZZZ99')); // AAA00
References
String.prototype.charCodeAt()
String.prototype.replace()
String.prototype.padStart()
String.prototype.slice()
String.fromCharCode()
parseInt()
Number.prototype.toString()
String.prototype.match()
You could take two function for gettign a deciaml or the fancy value and check if the last digit is nine.
function increment(value) {
const
decimal = s => Array
.from(s, v => parseInt(v, 36) - 10)
.reduce((s, v) => s * 26 + v, 0),
fancy = n => Array
.from(n.toString(26), v => (parseInt(v, 26) + 10).toString(36))
.join('')
.toUpperCase(),
[left, right] = value.match(/\D+|\d+/g);
if (value === 'ZZ9') return 'AA0';
return right === '9'
? fancy(decimal(left) + 1) + '0'
: left + (+right + 1);
}
console.log(increment('AA0')); // AA1
console.log(increment('AZ9')); // BA0
console.log(increment('ZZ9')); // AA0

Need help solving a javascript Caesar Cipher problem

I'm stuck doing the Caesar cipher problem. For those of you familiar with the problem, I'm not able to wrap around the alphabet, for example if I want to shift the string 'z' by 1, instead of getting 'a', i'll get '['. I know the reason this happens but I'm not able to come up with the proper code. Any help will be appreciated.
Here's my code:
const caesar = function(word, num) {
let solved = ""
num = num % 26;
for (let i = 0; i < word.length ; i++) {
let ascii = word[i].charCodeAt();
if ((ascii >= 65 && ascii <= 90) || (ascii >= 97 && ascii <= 122)) {
solved += String.fromCharCode(ascii + num) ;
} else {
solved += word[i]
}
}
return solved;
}
You need to take the modulus under 26 after subtracting the char code of the first letter of the alphabet and add it back afterward to allow the cipher to wrap around. You will need to handle capital and lowercase letters separately.
const caesar = function(word, num) {
let solved = ""
num = (num%26 + 26) % 26;
for (let i = 0; i < word.length ; i++) {
let ascii = word[i].charCodeAt();
if ((ascii >= 65 && ascii <= 90)) {
solved += String.fromCharCode((ascii - 'A'.charCodeAt(0) + num)%26
+ 'A'.charCodeAt(0)) ;
} else if(ascii >= 97 && ascii <= 122){
solved += String.fromCharCode((ascii-'a'.charCodeAt(0) + num) % 26
+ 'a'.charCodeAt(0));
} else {
solved += word[i]
}
}
return solved;
}
console.log(caesar("abcdefghijklmnopqrstuvwxyzABCDEFGHI", 7));
Do the modulus when you add num to your ascii value. This way you don't scroll past the end of the range (and loop around if you are through the modulus (remainder)).
solved += String.fromCharCode((ascii + num)%26) ;
Out of interest, the ASCII codes for 'A` and 'a' are 0x41 and 0x61 respectively: upper and lower case letters differ by whether bit 0x20 is set (lower case) or not set (upper case).
Hence a bit-bashing algorithm to circular shift ASCII letters and maintain case would be strip the lower case bit, perform the shift, and re-insert the case bit:
"use strict";
function caesarShiftLetter( letter, num) {
let code = letter.charCodeAt(0);
let lowerCaseBit = code & 0x20; // 0 or 0x20
let upperCaseCode = code - lowerCaseBit;
if( upperCaseCode < 0x41 || upperCaseCode >= 0x41 + 26) {
return letter;
}
num = 26 + num%26; // handle large negative shift values
upperCaseCode = ((upperCaseCode - 0x41) + num) % 26 + 0x41;
return String.fromCharCode( upperCaseCode | lowerCaseBit);
}
// to test:
function caesarShiftString( str, num) {
return Array.from(str).map(char => caesarShiftLetter( char, num)).join('');
}
console.log( caesarShiftString(
"abc ... xyz, ABC ... XYZ, I, II, III, IV, V, VI, VII, VIII, IX, X - 1,3,4,5,6,7,9, 10",-22
)
);

Is there a more concise way to set up a conditional statement to execute for an arbitrary set of values of a variable? [duplicate]

This question already has answers here:
JavaScript: Simple way to check if variable is equal to one of two or more values? [duplicate]
(8 answers)
Closed 7 years ago.
Is there a more efficient/ concise/ eloquent way to write this:
else if ((aInd === 3)||(aInd === 7)||(aInd === 9)||(aInd === 19)
letter = alphabet[aInd + 1].toUpperCase();
Is there any valid syntax that looks like
if (a === (3 || 7 || 13 || 19) {do this}
... or lets you group sets of values of for a single variable in a more concise way than a bunch of boolean expressions with || logic?
Background: Novice programmer, working through a basic cypher challenge on coderbyte that requires taking a certain action (capitalizing) if the letter is a vowel. For reasons of simplicity (because it's used elsewhere in the program) I declared an array alphabet containing each letter a-z in the form of a string. The 'cypher' also transposes every letter one to the right, so the alphabet indexes of the letters to become vowels are 3, 7, 13, and 19. aInd represents the index of letter in the alphabet.
Full code:
function letterChanges(str) {
var alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
var words = str.toLowerCase().split(' '), senArray = words.map(function(word) {return word.split('')});
senArray.forEach(function(word) {
word = word.filter(function(letter, index, word) {
if ((Boolean(alphabet.indexOf(letter))) === false) return false;
else return true;
});
});
senArray[0].map(function(letter) {
var aInd = alphabet.indexOf(letter);
switch (aInd) {
case 25:
letter = alphabet[aInd].toUpperCase();
break;
case (3 || 7 || 13 || 19):
letter = alphabet[aInd + 1].toUpperCase();
console.log(letter);
break;
default:
letter = alphabet[aInd + 1];
break;
}
return letter;
})
return senArray.map(function(word) {
return word.map(function(letter) {
var aInd = alphabet.indexOf(letter);
if (aInd === 25) {letter = alphabet[aInd].toUpperCase();}
else if ((aInd === 3)||(aInd === 7)||(aInd === 13)||(aInd === 19)) {letter = alphabet[aInd + 1].toUpperCase();}
else {letter = alphabet[aInd + 1];}
return letter;
}).join('');
}).join(' ');
}
letterChanges("Input string goes here.");
Pass the values as an array and check the indexOf.
In your case,
if ([3, 7, 13, 19].indexOf(aInd) > -1) {
letter = alphabet[aInd + 1].toUpperCase();
}

Categories

Resources