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;
}
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.
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;
}
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