Javascript fails to give correct output in IE - javascript

<script>
// This would be the place to edit if you want a different
// Base32 implementation
var alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ012345'
/**
* Build a lookup table and memoize it
*
* Return an object that maps a character to its
* byte value.
*/
var lookup = function() {
var table = {}
// Invert 'alphabet'
for (var i = 0; i < alphabet.length; i++) {
table[alphabet[i]] = i
}
lookup = function() { return table }
return table
}
// Functions analogously to Encoder
function Decoder() {
var skip = 0 // how many bits we have from the previous character
var byte = 0 // current byte we're producing
this.output = ''
// Consume a character from the stream, store
// the output in this.output. As before, better
// to use update().
this.readChar = function(char) {
if (typeof char != 'string'){
if (typeof char == 'number') {
char = String.fromCharCode(char)
}
}
//char = char.toLowerCase()
var val = lookup()[char]
if (typeof val == 'undefined') {
// character does not exist in our lookup table
return // skip silently. An alternative would be:
// throw Error('Could not find character "' + char + '" in lookup table.')
}
val <<= 3 // move to the high bits
byte |= val >>> skip
skip += 5
if (skip >= 8) {
// we have enough to preduce output
this.output += String.fromCharCode(byte)
skip -= 8
if (skip > 0) byte = (val << (5 - skip)) & 255
else byte = 0
}
}
this.finish = function(check) {
var output = this.output + (skip < 0 ? alphabet[bits >> 3] : '') + (check ? '$' : '')
this.output = ''
return output
}
}
Decoder.prototype.update = function(input, flush) {
for (var i = 0; i < input.length; i++) {
this.readChar(input[i])
}
var output = this.output
this.output = ''
if (flush) {
output += this.finish()
}
return output
}
/** Convenience functions
*
* These are the ones to use if you just have a string and
* want to convert it without dealing with streams and whatnot.
*/
// Base32-encoded string goes in, decoded data comes out.
function decode(input) {
var decoder = new Decoder()
var output = decoder.update(input.split("").reverse().join("")+'A', true)
return output
}
function toHex(str) {
var hex = '';
for(var i=0;i<str.length;i++) {
//hex += ''+("00" + str.charCodeAt(i).toString(16)).substr(-2);
hex += str.charCodeAt(i).toString(16);
}
return hex;
}
convertHex = toHex(decode('A0C4KB'));
alert(convertHex);
</script>
The above script works fine on FF and Chrome and gives me the correct hex value.
The alert output comes as expected with
abc2d0
For IE, this doesn't seem to work. I get all
ffffffff
This is a Base32 implementation that I pickep up from https://github.com/agnoster/base32-js

Internet Explorer's JScript engine doesn't support array access to string constants. You'll have to replace alphabet[i] with alphabet.charAt(i) to get it working. I thought MS had addressed this issue, though, but I could be wrong/too hopeful.

Related

Converting a 64 bit HEX to Decimal Floating-Pointt in Javascript

So basically I have a couple of numbers that come out as HEX values in the form of "3FF0000000000000" and I want to get float values of out these, pretty much like in here So in this particular case I'd expect "20.000000000000000" as a result - which I'll later trim to only 5 decimals, but that should be easy enough.
I've tried a couple of solutions but unfortunately I know too little about conversions (and javascript aswell) to know exactly what I might be doing wrong.
The latest try looks something like this:
const hexToFloat64 = (hex) => {
var int32 = [],
float64;
if (hex.length > 4) {
var high = hex.substr(0, 8),
low = hex.substr(8, 8);
int32.push(parseInt(high, 16), parseInt(low, 16));
}
var uint32 = new Uint32Array(int32);
float64 = new Float64Array(uint32.buffer);
var returnValue = float64[0];
return returnValue;
};
Much obliged!
This is NOT an answer to your exact problem. It IS a solution to decode the hex. Thats all i am doing here. I have no context to solve your problem.
function convHexStringToString(ss) {
// ss length must be even (or 0) when passed to this function
var s = "";
var p;
if (ss.length > 0) {
if (ss.length % 2 == 0) {
var l = Math.floor(ss.length / 2); // floor must never have to do work
for (var i = 0; i < l; i++) {
var i2 = i * 2;
if (ss.charAt(i2) != "0") {
p = ss.charAt(i2) + ss.charAt((i2) + 1);
}
else {
p = ss.charAt((i2) + 1);
}
d = parseInt(p,16);
s += String.fromCharCode(d);
}
}
}
return s;
}

How to match and group strings efficiently in Javascript?

Write a function that returns an integer indicating number of times a group of string "pzmcb" appears in a string in no particualr orther. for example
input string 1 -> "abdpsclmhz"
output 1 -> 1
input string 2 : pzmcbcbpzmpcm
output 2: 2
I have written the code but it is not efficient and cannot handle large input string. I will appreciate it if an efficent way of writing this function can be provided
'use strict';
//pmzcbpmzcbpmz [0 -4] [5 - 9] returns 2
function matchGroup(word) {
let regex = /[pzmcb]/g
let stringArray = word.match(regex);
//console.log(stringArray);
let cloneArray = [...stringArray];
let stored = [];
let searchString = "";
let secondString = "";
let temp = "";
let tempArray = [];
stringArray.forEach(item => {
if (cloneArray.indexOf(item) >= 0 && searchString.indexOf(item) === -1) {
searchString += item;
if (searchString.length === 5) {
stored.push(searchString);
searchString = "";
}
} else if(secondString.indexOf(item) === -1){
secondString += item;
if (secondString.length === 5) {
stored.push(searchString);
secondString = "";
}
}else {
temp += item;
if (temp.length === 5) {
tempArray.push(temp);
temp = "";
}
}
});
return stored.length;
// return integer
}
var paragraph = 'pzmcbpdfbcmz';
let result = matchGroup("abcdefpfklmhgzpzmcbpdfbcmzjklmoplzdsaklmcxheqgexcmpzdhgiwqertyhgdsbnmkjilopazxcsdertijuhgbdmlpoiqarstiguzcmnbgpoimhrwqasfgdhuetiopmngbczxsgreqad");
console.log(result);
I expect that the matchGroup function to return exact integers for large inputs
I'd build up a map of character counts:
function countChars(str) {
const count = {};
for(const char of str) count[char] = (count[char] || 0) + 1;
return count;
}
Now we can easily build up count maps of the string to find and the source:
const toFind = countChars("pzmbc"),
source = countChars("pzmcbpdfbcmz");
Now we can find the smallest relationship of chars to find and chars that are there:
const result = Math.min(
...Object.entries(toFind).map(([char, need]) => Math.floor((source[char] || 0) / need))
);
function countChar(char, string) {
return (string.match(new RegExp(char, "g")) || []).length;
}
function countDistinctSubstring(sub, string) {
firstChars = {};
for (i = 0; i < sub.length; i++) {
if (sub[i] in firstChars)
firstChars[sub[i]]++;
else
firstChars[sub[i]] = 1;
}
return Math.min(...Object.keys(firstChars).map(key => Math.floor(countChar(key, string) / firstChars[key])));
}
> countDistinctSubstring("pzmcb", "abdpsclmhz");
< 1
> countDistinctSubstring("pzmcb", "pzmcbcbpzmpcm");
< 2
> countDistinctSubstring("pzmcbpdfbcmz", "abcdefpfklmhgzpzmcbpdfbcmzjklmoplzdsaklmcxheqgexcmpzdhgiwqertyhgdsbnmkjilopazxcsdertijuhgbdmlpoiqarstiguzcmnbgpoimhrwqasfgdhuetiopmngbczxsgreqad");
< 3
I can't tell for sure, but I think this is what you are looking for. It counts the number of occurrences of each letter in the small string, then finds the minimum ratio of occurrences in the large string to those in the small string for each character. This minimum ratio is the maximum number of distinct times the small string can be composed of letters from the larger one.
Note that this answer was used in making the countChar function.

Javascript String.charAt(i) and string[i] give a different result?

I wrote a short function to split a string into an array of words (using a loop -- this was an exercise, I don't claim it's pretty code). It works fine when I use String.charAt() to access a character but doesn't when I use string[i]. Shouldn't these give the same results?
"use strict"
function whitespace(ch) {
return (ch == ' ') || (ch == '\t') || (ch == '\n');
}
function splitToWords(string) {
var words = [];
var wordStart = 0;
var inWord = false;
var isWhitespace;
for (var i = 0; i <= string.length; i++) {
//this works fine
isWhitespace = whitespace(string.charAt(i));
// but this doesn't -- causes the final test (below) to fail
// isWhitespace = whitespace(string[i]);
if (inWord && isWhitespace) {
words.push(string.slice(wordStart, i));
inWord = false;
} else if (!inWord && !isWhitespace) {
wordStart = i;
inWord = true;
}
}
if (inWord) words.push(string.slice(wordStart, i));
return words;
}
This test passes when I use String.charAt() but fails using index access to the string
var words = splitToWords(' ');
console.log(words.length === 0); // => true
Shouldn't the two modes of access give the same result? Thanks for any help in pointing out my error!

Split a variable using mathematical equations in javascript

I have two questions actually.
What I want to do is 1st to check if the user entered value is a correct mathematical equation. For example, if the use enters x + y ( z this should detect as an invalid formula and x + y ( z ) as a correct one,
The 2nd thing I want to do is to split the formula from the + - * / () signs, so the above formula will be return as x, y, z.
What I have done is bellow
var arr = [];
var s = 'x + y ( z )';
arr = s.split("(?<=[-+*/])|(?=[-+*/])");
console.log(arr);
This returns a single array with just one data like, [x + y ( z )]
Another thing, the variables are not single letters. they could be
words like, annual price, closing price, etc
Can someone help me in this problem. Thanks in advance
UPDATE : I have tried "/[^+/*()-]+/g" also
For the second part:
var s = 'x + y ( z )';
var arr = s.match(/(\w)/g);
console.log(arr);
document.write(JSON.stringify(arr));
Of course, you have to check the validity of the input first.
Edit: using Tomer W's answer suggesting eval():
function checkExpression(str) {
// check for allowed characters only
if (/[^\w\d\(\)\+\*\/\-\s]/.exec(s) != null)
return false;
// extract variable names, assuming they're all one letter only
var arr = s.match(/(\w+)/g);
// instantiate the variables
arr.forEach(function (variable) {
eval(variable + '= 1');
});
// ( is alone, replace it by * (
str = str.replace(/\(/g, '* (');
try {
eval(str);
return true;
}
catch (ex) {
console.log(ex);
return false;
}
}
It's dirty but it works most of the time (Tomer W pointed some edge cases like ++62+5 or 54++++6 that can be avoided with an another regex check), do you have more complicated example to test?
Word of warning
VERY VERY VERY DANGEROUS METHOD AHEAD !!!
I am posting this as it is a valid answer, but you should do it only with extreme caution as a user can totally mess up your site.
DO not let the one user input be used in eval for another user !!! EVER !!!
Actual answer
You can use the built-in java-script compiler of your browser, and use eval()
function checkEq(equ)
{
for(ch in equ){
// check that all characters in input are "equasion usable"
if(" +-*/1234567890e^&%!=".indexOf(ch) === -1)
{ // if there are invalid chars
return false;
}
}
try{
// try running the equ, will throw an exception on a syntax error.
eval(equ);
return true; // no exception
}
catch(ex){
return false; // syntax error
}
}
Plunker example
and as i noted before! extreme caution!
Using both #ShanShan and #Tomer W answers, I wrote a formula validator. the code is bellow. In this validator, I checks for opening and closing brackets, extra / * - + signs, unwanted symbols, etc.
If the user wants to create and validate a formula with x,y,z
variables, user have to add the variables to an array and pass it to
this validator with the formula written so the validator accepts the
variables which are not numbers.
I also used a custom set mentioned in this post. https://stackoverflow.com/a/4344227/918277
Important : This java script function can't validate very complex formulas with sin, cos, tan, log, etc. Script will identify them as just letters and will return false.
function StringSet() {
var setObj = {}, val = {};
this.add = function(str) {
setObj[str] = val;
};
this.contains = function(str) {
return setObj[str] === val;
};
this.remove = function(str) {
delete setObj[str];
};
this.values = function() {
var values = [];
for ( var i in setObj) {
if (setObj[i] === val) {
values.push(i);
}
}
return values;
};
}
/**
*
* #param _formulaInputs
* Array of use entered inputs to be use in formula
* #param _formula
* User entered formula
* #returns {Boolean}
*/
function validateFormula(_formulaInputs, _formula) {
var formula = _formula;
var bracketStack = new Array();
var formulaDescArray = [];
var formulaDescInForm = new StringSet();
for (var i = 0; i < _formulaInputs.length; i++) {
formulaDescInForm.add(_formulaInputs[i]);
}
/* Regex to check for unwanted symbols(! # # $ etc.) */
if (/[^\w\d\(\)\+\*\/\-\s]/.exec(formula) != null) {
return false;
}
for (var i = 0; i < _formula.length; i++) {
if ((_formula.charAt(i) == '/' || _formula.charAt(i) == '*'
|| _formula.charAt(i) == '-' || _formula.charAt(i) == '+')
&& (_formula.charAt(i + 1) == '/'
|| _formula.charAt(i + 1) == '*'
|| _formula.charAt(i + 1) == '-' || _formula
.charAt(i + 1) == '+')) {
return false;
}
}
var lastChar = formula.charAt(formula.length - 1);
if (lastChar == '/' || lastChar == '*' || lastChar == '-'
|| lastChar == '+') {
return false;
}
formulaDescArray = formula.split(/[\/\*\-\+\()]/g);
/* Remove unwanted "" */
for (var i = 0; i < formulaDescArray.length; i++) {
if (formulaDescArray[i].trim().length == 0) {
formulaDescArray.splice(i, 1);
i--;
}
}
/* Remove unwanted numbers */
for (var i = 0; i < formulaDescArray.length; i++) {
if (!isNaN(formulaDescArray[i])) {
formulaDescArray.splice(i, 1);
i--;
}
}
for (var i = 0; i < formulaDescArray.length; i++) {
if (!formulaDescInForm.contains(formulaDescArray[i].trim())) {
return false;
}
}
for (var i = 0; i < formula.length; i++) {
if (formula.charAt(i) == '(') {
bracketStack.push(formula.charAt(i));
} else if (formula.charAt(i) == ')') {
bracketStack.pop();
}
}
if (bracketStack.length != 0) {
return false;
}
return true;
}

Javascript: Split a string by comma, except inside parentheses

Given string in the form:
'"abc",ab(),c(d(),e()),f(g(),zyx),h(123)'
How can I split it to get the below array format:
abc
ab()
c(d(),e())
f(g(),zyx)
h(123)
I have tried normal javascript split, however it doesn't work as desired. Trying Regular Expression but not yet successful.
You can keep track of the parentheses, and add those expressions when the left and right parens equalize.
For example-
function splitNoParen(s){
var left= 0, right= 0, A= [],
M= s.match(/([^()]+)|([()])/g), L= M.length, next, str= '';
for(var i= 0; i<L; i++){
next= M[i];
if(next=== '(')++left;
else if(next=== ')')++right;
if(left!== 0){
str+= next;
if(left=== right){
A[A.length-1]+=str;
left= right= 0;
str= '';
}
}
else A=A.concat(next.match(/([^,]+)/g));
}
return A;
}
var s1= '"abc",ab(),c(d(),e()),f(g(),zyx),h(123)';
splitNoParen(s1).join('\n');
/* returned value: (String)
"abc"
ab()
c(d(),e())
f(g(),zyx)
h(123)
*/
This might be not the best or more refined solution, and also maybe won't fit every single possibility, but based on your example it works:
var data = '"abc",ab(),c(d(),e()),f(g(),zyx),h(123)';
// Create a preResult splitting the commas.
var preResult = data.replace(/"/g, '').split(',');
// Create an empty result.
var result = [];
for (var i = 0; i < preResult.length; i++) {
// Check on every preResult if the number of parentheses match.
// Opening ones...
var opening = preResult[i].match(/\(/g) || 0;
// Closing ones...
var closing = preResult[i].match(/\)/g) || 0;
if (opening != 0 &&
closing != 0 &&
opening.length != closing.length) {
// If the current item contains a different number of opening
// and closing parentheses, merge it with the next adding a
// comma in between.
result.push(preResult[i] + ',' + preResult[i + 1]);
i++;
} else {
// Leave it as it is.
result.push(preResult[i]);
}
}
Demo
For future reference, here's another approach to top-level splitting, using string.replace as a control flow operator:
function psplit(s) {
var depth = 0, seg = 0, rv = [];
s.replace(/[^(),]*([)]*)([(]*)(,)?/g,
function (m, cls, opn, com, off, s) {
depth += opn.length - cls.length;
var newseg = off + m.length;
if (!depth && com) {
rv.push(s.substring(seg, newseg - 1));
seg = newseg;
}
return m;
});
rv.push(s.substring(seg));
return rv;
}
console.log(psplit('abc,ab(),c(d(),e()),f(g(),zyx),h(123)'))
["abc", "ab()", "c(d(),e())", "f(g(),zyx)", "h(123)"]
Getting it to handle quotes as well would not be too complicated, but at some point you need to decide to use a real parser such as jison, and I suspect that would be the point. In any event, there's not enough detail in the question to know what the desired handling of double quotes is.
You can't use .split for this, but instead you'll have to write a small parser like this:
function splitNoParen(s){
let results = [];
let next;
let str = '';
let left = 0, right = 0;
function keepResult() {
results.push(str);
str = '';
}
for(var i = 0; i<s.length; i++) {
switch(s[i]) {
case ',':
if((left === right)) {
keepResult();
left = right = 0;
} else {
str += s[i];
}
break;
case '(':
left++;
str += s[i];
break;
case ')':
right++;
str += s[i];
break;
default:
str += s[i];
}
}
keepResult();
return results;
}
var s1= '"abc",ab(),c(d(),e()),f(g(),zyx),h(123)';
console.log(splitNoParen(s1).join('\n'));
var s2='cats,(my-foo)-bar,baz';
console.log(splitNoParen(s2).join('\n'));
Had a similar issue and existing solutions were hard to generalize. So here's another parser that's a bit more readable and easier to extend to your personal needs. It'll also work with curly braces, brackets, normal braces, and strings of any type. License is MIT.
/**
* This function takes an input string and splits it by the given token, but only if the token is not inside
* braces of any kind, or a string.
* #param {string} input The string to split.
* #param {string} split_by Must be a single character.
* #returns {string[]} An array of split parts without the split_by character.
*/
export function parse_split(input:string, split_by:string = ",") : string[]
{
// Javascript has 3 types of strings
const STRING_TYPES = ["'","`","\""] as const;
// Some symbols can be nested, like braces, and must be counted
const state = {"{":0,"[":0,"(":0};
// Some cannot be nested, like a string, and just flip a flag.
// Additionally, once the string flag has been flipped, it can only be unflipped
// by the same token.
let string_state : (typeof STRING_TYPES)[number] | undefined = undefined
// Nestable symbols come in sets, usually in pairs.
// These sets increase or decrease the state, depending on the symbol.
const pairs : Record<string,[keyof typeof state,number]> = {
"{":["{",1],
"}":["{",-1],
"[":["[",1],
"]":["[",-1],
"(":["(",1],
")":["(",-1]
}
let start = 0;
let results = [];
let length = input.length;
for(let i = 0; i < length; ++i)
{
let char = input[i];
// Backslash escapes the next character. We directly skip 2 characters by incrementing i one extra time.
if(char === "\\")
{
i++;
continue;
}
// If the symbol exists in the single/not nested state object, flip the corresponding state flag.
if(char == string_state)
{
string_state = undefined;
console.log("Closed string ", string_state);
}
// if it's not in a string, but it's a string opener, remember the string type in string_state.
else if(string_state === undefined && STRING_TYPES.includes(char as typeof STRING_TYPES[number]))
{
string_state = char as typeof STRING_TYPES[number];
}
// If it's not in a string, and if it's a paired symbol, increase or decrease the state based on our "pairs" constant.
else if(string_state === undefined && (char in pairs) )
{
let [key,value] = pairs[char];
state[key] += value;
}
// If it's our split symbol...
else if(char === split_by)
{
// ... check whether any flags are active ...
if(Object.entries(state).every(([k,v])=>v == 0) && (string_state === undefined))
{
// ... if not, then this is a valid split.
results.push(input.substring(start,i))
start = i+1;
}
}
}
// Add the last segment if the string didn't end in the split_by symbol, otherwise add an empty string
if(start < input.length)
{
results.push(input.substring(start,input.length))
}
else
results.push("");
return results;
}
With this regex, it makes the job:
const regex = /,(?![^(]*\))/g;
const str = '"abc",ab(),c(d(),e()),f(g(),zyx),h(123)';
const result = str.split(regex);
console.log(result);
Javascript
var str='"abc",ab(),c(d(),e()),f(g(),zyx),h(123)'
str.split('"').toString().split(',').filter(Boolean);
this should work

Categories