Trying to get a JS function to work that shifts the individual characters in a string by a set amount (and then returns the new "shifted" string). I'm using ROT-13 (so A-M are shifted down 13 characters and N-Z are shifted up 13 characters).
The trouble lies with this piece of code:
if (arr[i] <= 77) {
finalStr += String.fromCharCode(arr[i] + 13);
This code should shift E to R.
E (69) + 13 = R (82)
However, the characters in the returned string that should be shifted down 13 spaces return as weird symbols.
"FᬁEEC᧕DECAMᨹ"
function rot13(str) {
var newStr = "";
var finalStr = "";
for (i = 0, j = str.length; i < j; i++) {
newStr += str.charCodeAt(i);
newStr += " ";
}
var arr = newStr.split(" ");
arr.pop();
for (i = 0, j = arr.length; i < j; i++) {
if (arr[i] !== 32) {
if (arr[i] <= 77) {
finalStr += String.fromCharCode(arr[i] + 13);
}
else {
finalStr += String.fromCharCode(arr[i] - 13);
}
}
}
return finalStr;
}
rot13("SERR PBQR PNZC");
The problem doesn't appear to be what you identified but rather your handling of the conversion from characters to character codes. Simplifying and cleaning up your conversioin logic seems to fix the problem:
function rot13(str) {
var arr = new Array();
for (var i = 0; i < str.length; i++) {
arr[arr.length] = str.charCodeAt(i);
}
var finalStr = "";
for (var i = 0; i < arr.length; i++) {
if (arr[i] !== 32) {
if (arr[i] <= 77) {
finalStr += String.fromCharCode(arr[i] + 13);
} else {
finalStr += String.fromCharCode(arr[i] - 13);
}
} else {
finalStr += String.fromCharCode(32);
}
}
return finalStr;
}
rot13("SERR PBQR PNZC");
Which returns "FREE CODE CAMP".
And just to blow your mind a little more:
var rot13=function(str){
return str.split('')
.map(function(ch){
var v=ch.charCodeAt(0);
return String.fromCharCode(v > 77 ? v-13 : v+13);
})
.join('');
};
UPDATE - Version that handles both upper and lower-cased letters
var rot13 = function(s){
return s.split('').map(function(c){
var v=c.toLowerCase().charCodeAt(0);
if(v<97 || v>122) return c;
var t = v>=96,
k = (v - 96 + 12) % 26 + 1;
return String.fromCharCode(k + (t ? 96 : 64));
}).join('');
};
rot13('SERR PBQR PNZC') // => FREE CODE CAMP
Just had an idea : why not doing it on one line only ? And by the way, I looked at the Free Code Camp challenge and u have to bypass all non alphanumerical characters. Here it is :
function rot13(str) { // LBH QVQ VG!
return str.split('').map(function(letter){
return letter.match(new RegExp(/\W/i)) ? letter : (letter.charCodeAt(0) <= 77 ? String.fromCharCode(letter.charCodeAt(0) + 13) : String.fromCharCode(letter.charCodeAt(0) - 13));
}).join('');
}
// Change the inputs below to test
rot13("SERR PBQR PNZC"); // FREE CODE CAMP
TADAAAAH :-)
Here is the pen : http://codepen.io/liorchamla/pen/mPwdEz/
Hope u will like it and also hope you will try hard to understand this !
Happy Free Code Camp to all !
Related
I want to take the var ascii and put it into a string. The code only returns each char within the loop.
function rot13(str) { // LBH QVQ VG!
var newStr = str;
for (var i = 0; i < str.length; i++){
var letter = str.charAt(i);
var code = letter.charCodeAt();
if (code > 77){
ascii = code - 13;
}
else if (code === 32 ){
ascii = code;
}
else{
var ascii = code + 13;
}
}
}
rot13("SERR PBQR PNZC"); //returns FREE CODE CAMP
To answer you, you already have written the code, but just used messed up a bit here and there -
function rot13(str) { // LBH QVQ VG!
console.log (str);
var newStr = str;
var ascii = "";
for (var i = 0; i < newStr.length; i++){
var letter = newStr.charAt(i);
//console.log (letter);
var code = letter.charCodeAt();
//console.log (code);
if (code > 77){
ascii = code - 13;
//console.log (ascii);
}
else if (code === 32 ){
ascii = code;
//console.log (ascii);
}
else{
ascii = code + 13;
//console.log (ascii);
}
var sipher = "";
sipher = String.fromCharCode(ascii);
newStr += sipher;
}
console.log (sipher);
return newStr;
}
This is my code:
function pars(str) {
var p = [str.split("(").length - 1, str.split(")").length - 1];
if (p[0] > p[1]) {
for (var i = 0; i < (p[0] - p[1]); i++) {
str += ")";
}
}
return str;
}
It adds parentheses in the end of the string if it's missing.
Examples:
"((asd)s" -> "((asd)s)"
"(((ss)123" -> "(((ss)123))"
How can I make this work for beginning parentheses aswell?
Like:
"))" -> "(())"
")123))" -> "((()123))"
Here is a simple stack-based approach. The full JSFiddle is below as well as list of confirmed test cases.
function pars(s) {
var missedOpen = 0, stack = new Array();
for (i = 0; i < s.length; i++) {
if (s[i] == '(') {
stack.push(s[i]);
} else if (s[i] == ')') {
if (!stack.pop())
missedOpen++;
}
}
return Array(missedOpen + 1).join('(') + s + Array(stack.length + 1).join(')');
}
Confirmed Test cases:
// Target: Expected
var cases = {
'()': '()',
')(': '()()',
'(': '()',
')': '()',
'This)(is))a((test)': '((This)(is))a((test))',
'(A)': '(A)',
')A(': '()A()'
};
See the complete JSFiddle is here.
As noted by a comment, here's a version without the array at all. This should be the most efficient method. All the test cases passed.
function pars(s) {
var missedOpen = 0, missedClosed = 0;
for (i = 0; i < s.length; i++) {
if (s[i] == '(') {
missedClosed++;
} else if (s[i] == ')') {
if (missedClosed > 0)
missedClosed--;
else
missedOpen++;
}
}
return Array(missedOpen + 1).join('(') + s + Array(missedClosed + 1).join(')');
}
You need both the number of unmatched beginning parenthesis and the number of unmatched end parenthesis. Here is a rough solution:
function pars(str) {
var p = 0;
var minp = 0;
for (var i = 0; i < str.length; i++) {
if (str[i] == "(") p++;
if (str[i] == ")") {
p--;
if (p<minp) minp = p;
}
}
for (i = 0; i > minp; i--) {
str = "(" + str;
}
p = p - minp; // If we added any starting parenthesis, we need to end those as well.
for (i = 0; i < p; i++) {
str = str + ")";
}
return str;
}
This one seems to work:
function pars(str){
var pars = [].reduce.call(str, function(acc, letter){
if(letter === '(') { acc.right++;}
else if(letter === ')') {
if(acc.right) {acc.right--;}
else {acc.left++;}//no starting one
}
return acc;
}, {left: 0, right: 0}),
left = pars.left,
right = pars.right;
if(left) { str = new Array(left+1).join('(') + str;}
if(right) { str += new Array(right+1).join(')');}
return str
}
var str = ')))(((fdfd)fd)('
$("#out").html(str + " - " + pars(str))
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="out"/>
This is an extremely dirty solution (which works in Firefox for the time being due to repeat function):
function pars(str) {
var t = str;
var n;
while ((n = t.replace(/\([^()]*\)/g, "")) != t) {
t = n;
}
var open = t.match(/\)/g);
var close = t.match(/\(/g);
return "(".repeat(open.length) + str + ")".repeat(close.length);
}
Basically, it matches all pairs of (), then count the number of ( and ), and append ) and ( accordingly.
A clean solution should use a counter to count the number of opening unmatched parentheses. It will discard and count the number of unmatched ). For the number of unmatched (, do as per normal. It will be a one-pass solution, instead of multi-pass solution like the one above.
You can use a variation on the famous stack based bracket matching algorithm here.
The general idea is that you scan the code and push an opening parenthesis onto the stack when you see one, then when you see a closing one you pop the top value from the stack and continue. This will ensure that you have the correct balance.
(123())
// ( - push -> ['(']
// 1 - nothing
// 2 - nothing
// 3 - nothing
// ( - push -> ['(', '(']
// ) - pop -> ['(']
// ) - pop -> []
However, we want to bend the rules slightly.
If we push a closing paren onto the stack, and the stack is empty: we need to add an opening paren to the start of the string
If we arrive at the end of the string and there are still open parens on the stack, then we need to close them.
So the code would look something like this:
function parse(str) {
var stack = []
out = str,
idx = 0,
chr = '';
for(idx = 0; idx < str.length; idx++) {
chr = str[idx];
if(chr === '(') {
stack.push(chr);
}
else if(chr === ')') {
if(stack.length > 0) {
stack.pop();
} else {
out = '(' + out;
}
}
}
for(idx = 0; idx < stack.length; idx++) {
out = out + ')';
}
return out;
}
Bonus: Because of the iterative stack based nature of this algorithm, it will generally be faster than RegEx alternatives.
Just scan the string, counting parens. +1 for (, -1 for ). If the number goes negative, you're missing a ( at the beginning. If, when you are finished, the number is positive, then that's how many )s you need to add at the end.
var addmissingparens = function(s){
var n = 0;
Array.prototype.forEach.call(s, function(c){
if(c === '('){
n += 1;
}
if(c === ')'){
if(n === 0){
s = '(' + s;
}else{
n -= 1;
}
}
});
for(; n>0; n-=1){
s += ')';
}
return s;
};
I'm new to Javascript and wrote the code below to determine if a string is a palindrome. I'm curious as to what is the most efficient way to accomplish the same task.
var isPalindrome = function (string) {
var leftString = [];
var rightString = [];
// Remove spaces in the string and convert to an array
var strArray = string.split(" ").join("").split("");
var strLength = strArray.length;
// Determine if the string is even or odd in length, then assign left and right strings accordingly
if (strLength % 2 !== 0) {
leftString = strArray.slice(0, (Math.round(strLength / 2) - 1));
rightString = strArray.slice(Math.round(strLength / 2), strLength);
} else {
leftString = strArray.slice(0, (strLength / 2));
rightString = strArray.slice((strLength / 2, strLength))
}
if (leftString.join("") === rightString.reverse().join("")) {
alert(string + " is a palindrome.");
} else {
alert(string + " is not a palindrome.")
}
}
isPalindrome("nurses run");
It's not clear if you're talking about efficiency in terms of code length, or amount of computation, but this should be fairly good in both regards. And it takes into account non-alpha characters beside spaces as well as capitalization:
function isPalindrome(str) {
var i, len;
str = str.toLowerCase().replace(/[^a-z]/g, '');
len = str.length;
for(i = 0; i < len / 2; i += 1) {
if(str.charCodeAt(i) != str.charCodeAt(len - i - 1)) {
return false;
}
}
return true;
}
A much shorter approach (though perhaps more computation intensive):
function isPalindrome(str) {
str = str.toLowerCase().replace(/[^a-z]/g, '');
return str == str.split("").reverse().join("");
}
And if you really want that alert stuff, I'd suggest putting it in a separate function:
function isPalindromeAlert(str) {
alert(str + "is " + (isPalindrome(str) ? "" : "not ") + "a palindrome.");
}
function isPalindrome( s )
{
var i = 0, j = s.length-1;
while( i < j )
if( s[i++].toLowerCase() != s[j--].toLowerCase() ) return false;
return true;
}
I think this one is lot simpler:
var isPalindrome = function (string) {
if (string == string.split('').reverse().join('')) {
alert(string + ' is palindrome.');
}
else {
alert(string + ' is not palindrome.');
}
}
See more: Palindrome check in Javascript
var str = "abcba";
var len = str.Lenght;
var index = 0;
while(index <= len/2 && str[index] == str[len - index - 1]) index++;
if(index == len/2) {
alert(string + " is a palindrome.");
}
else {
alert(string + " is not a palindrome.");
}
You made a few unnecesary operations.
To be efficient, you should avoid unnecessary computations. Ask yourself:
do you need to remove spaces?
do you need to convert to an array?
do you need to allocate new objects for the left and right strings?
do you need to reverse the string?
The checking can be done in a very simple loop:
var len=string.length;
for (int i=0; i<(len/2); i++) {
if (string[i] != string[len-i-1]) {
alert(string + " is not a palindrome.");
return;
}
}
alert(string + " is a palindrome.");
To ignore spaces and non-alpha numeric characters, it can be re-written as follows:
function isAlphaNumeric( chr ) {
return ( ((c >= 'a') && (c <= 'z')) ||
((c >= 'A') && (c <= 'Z')) ||
((c >= '0') && (c <= '9')) );
}
// Note - template taken from #Matt's answer!
function isPalindrome( string ) {
var i = 0, j = s.length-1;
while( i < j ) {
if (isAlphaNumeric(string[i])) {
if (isAlphaNumeric(string[j])) {
if ( string[i++].toLowerCase() != string[j--].toLowerCase() )
return false;
} else {
j--;
}
} else {
i++;
if (!isAlphaNumeric(string[j])) j--;
}
}
return true;
}
unreadable + unmaintainable + terse + efficient + recursive + non-branching
function isPalindrome(s,i) {
return (i=i||0)<0|| i>=s.length/2|| s[i]==s[s.length-1-i]&& isPalindrome(s,++i);
}
Fiddle: http://jsfiddle.net/namcx0yf/
New to the JavaScript language and need help creating a function which generates the following display.
abcdefghijklmnopqrstuvwxyz
bcdefghijklmnopqrstuvwxyz
cdefghijklmnopqrstuvwxyz
defghijklmnopqrstuvwxyz
.... and so on, all the way down to
xyz
yz
z
I am not asking for handouts, just a little kickstart for a beginner to get started! Links, hints, tips, anything helps! Thanks!
Arrays and loops are powerful when combined.
var alphabet = "abcdefghijklmnopqrstuvwxyz".split('');
console.log(alphabet.join(''));
while (alphabet.length > 0) {
alphabet.shift();
console.log(alphabet.join(''));
}
Edit:
If you really need your decremented alphabet to be left-padded, you can use this:
var alphabet = "abcdefghijklmnopqrstuvwxyz";
var letters = alphabet.split('');
var addPadding = (function (minLength) {
return function (shortString) {
if (shortString.length < minLength) {
return new Array(
minLength - shortString.length + 1
).join(' ') + shortString;
}
};
}(alphabet.length));
console.log(alphabet);
while (letters.length > 0) {
letters.shift();
console.log(addPadding(letters.join('')));
}
Edit:
Here is a much simpler answer:
function decrementingAlphabet () {
var alphabet = 'abcdefghijklmnopqrstuvwxyz';
function iterate(spaces, letters) {
if (letters.length > 0) {
console.log(spaces + letters);
iterate(spaces + ' ', letters.substring(1));
} else {
return;
}
}
iterate('', alphabet);
}
This is simple example.
var str = '';
for (var s=0; s < 26; ++s) {
str = '';
for (var i=0; i < 26 - s; ++i) {
str += String.fromCharCode(97+s+i);
}
document.write(str + "<br/>");
}
See http://jsfiddle.net/G5Gds
Hmm, maybe this will help put you on the right track?
var str = '';
// Find out what 'a' is in ASCII
var baseLetterCode = 'a'.charCodeAt(0);
// Loop once for each letter
for (var i = 0; i < 26; ++i) {
// Append to string
str += String.fromCharCode(baseLetterCode + i);
}
In character codes, small alphabets lie from 97 onwards(97 for a). You need to use 2 for loops to print such series.
Here is your jsfiddle demo:
var display='';
for(var i=97;i<123;i++){
var s='';
for(var j=i;j<123;j++){
s+= String.fromCharCode( j );
}
display+=s;
}
alert(display);
(function() {
var theENalphabet = [];
for (var charNow = "a".charCodeAt(0); charNow <= "z".charCodeAt(0); charNow += 1) {
theENalphabet.push(String.fromCharCode(charNow));
}
var isNow = 0;
function decrAlph(startAt) {
var alphString = "";
for (var i = startAt; i < theENalphabet.length; i += 1) {
alphString += theENalphabet[i];
}
console.log(alphString);
isNow++;
while (isNow < theENalphabet.length) {
decrAlph(startAt + 1);
}
};
decrAlph(0);
})();
The charCode getting could be abstracted into a function:
var getCharCode = function(el){
return String.prototype.charCodeAt.call(el, 0);
};
getCharCode("a"); // returns 97..
I'm trying to create the equivalent of PHP's unpack. I've noticed the project PHPJS doesn't have it. I need it for the implementation of base32_encode and base32_decode (using Crockford's alphabet '0123456789ABCDEFGHJKMNPQRSTVWXYZ').
I couldn't find it anywhere and judging from it's counterpart, PHPJS's pack function I doubt my version will be complete and bug free any time soon.
base32tohex = (function() {
var dec2hex = function(s) {
return (s < 15.5 ? "0" : "") + Math.round(s).toString(16)
}
, hex2dec = function(s) {
return parseInt(s, 16)
}
, base32tohex = function(base32) {
for (var base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", bits = "", hex = "", i = 0; i < base32.length; i++) {
var val = base32chars.indexOf(base32.charAt(i).toUpperCase());
bits += leftpad(val.toString(2), 5, "0")
}
for (i = 0; i + 4 <= bits.length; i += 4) {
var chunk = bits.substr(i, 4);
hex += parseInt(chunk, 2).toString(16)
}
return hex
}
, leftpad = function(str, len, pad) {
return len + 1 >= str.length && (str = new Array(len + 1 - str.length).join(pad) + str),
str
};
return base32tohex;
}
)()