How to parse both Int and Float in JSON in Crystal? - crystal-lang

Crystal JSON complains that it can't cast Int to Float, code below throws exception
JSON.parse("{\"v\":1}")["v"].as_f
How to parse it? In case when some values are Int "1" and some Floats "1.1"?

Crystal is comparatively strict with types here. You have to be more explicit.
Option 1.
Implement your own method. I'd recommend use a different name.
struct JSON::Any
def to_f : Float64?
case #raw
when Float64 then #raw.as(Float64)
when Int then #raw.as(Int).to_f
end
end
end
You can then call it as JSON.parse("{\"v\":1}")["v"].as_f
Option 2.
Inside your code do a check first.
my_v = JSON.parse("{\"v\":1}")["v"]
if my_v.as_f?
my_v.as_f
elsif my_v.as_i?
my_v.to_i.to_f
end

Related

Matlab regex ${numberFun($4)} - Undefined function 'numberFun' for input arguments of type 'char'

I read that in Matlab it is possible to include a function call inside a regex transformation like this $1double$2[${doubleTextNumber($4)}], assuming 1, 2, 3 to be some regex groups, and 4 to be a purely numeric group. The exact thing I want to do is to catch all arrays consisting of the type creal_T, replace the type with double and double the length of the array.
codeText = "typedef struct {
double tolRob;
creal_T Mt2o[704];
creal_T Ho2o[704];
creal_T Ht2t[704];
creal_T Zo2t[704];
creal_T Ztd[64];
} testType;"
So, I want the struct above to become:
typedef struct {
double tolRob;
double Mt2o[1408];
double Ho2o[1408];
double Ht2t[1408];
double Zo2t[1408];
double Ztd[128];
} SpdEstType;
In Matlab I have made a function to convert a number to text and double it:
function [doubleValue] = doubleTextNumber(inputNumber)
doubleValue = string(str2double(inputNumber)*2.0);
end
I also have a regex that I expect would find the number in each declaration and feed it to the function:
resultString = regexprep(
codeText,
'(?m)^(\W*)creal_T(\s*\w*)(\[([^\]]*\d+)\])',
"$1double$2[${doubleTextNumber($4)}]");
However, as I run this peace of code, Matlab gives me the following error msg:
Error using regexprep
Evaluation of 'doubleTextNumber($4)' failed:
Undefined function 'doubleTextNumber' for input arguments of type 'char'.
As far as I understand, I have made the method do conversion from char, and expect it also to accept this value from my regex. I have tested that it works when I input '704' or "704" directly, and also that the regex works appart from this insertion.
Why does not Matlab find the function from my regex? (they are in the same m file)
It looks like I had 3 issues with my original approach:
In order for regexprep() to recognize my function, it had to be moved to its own m-file. Simply calling a method from inside the same file did not work.
I was using https://regex101.com/ to edit the search expression, but even though it seemed to be selecting the number inside the brackets, group 4 did not get populated by regexprep() in Matlab. A new version did work, and populated group 3 with the numbers I wanted: (?m)^(\W*)creal_T(\s*\w*).([^\]]*\d*)\]
I also added more conversion options to my multiplication method in case the input was a combination of numbers and char arrays.
The final version of my regex call becomes:
resultString = regexprep(
codeText,
'(?m)^(\W*)creal_T(\s*\w*).([^\]]*\d*)\]',
"$1double$2[${multiplyTextNumbers($3,2)}]");
where multiplyTextNumbers() is defined in its own m file as
function [productText] = multiplyTextNumbers(inputFactorText1,inputFactorText2)
%MULTIPLY This method takes numbers as input, and acepts either string,
%char or double or any combination of the three. Returns a string with the
%resulting product.
if (isstring(inputFactorText1) || ischar(inputFactorText1))
inputFactor1 = str2double(inputFactorText1);
else
inputFactor1 = inputFactorText1;
end
if (isstring(inputFactorText2) || ischar(inputFactorText2))
inputFactor2 = str2double(inputFactorText2);
else
inputFactor2 = inputFactorText2;
end
productText = sprintf('%d',inputFactor1*inputFactor2);
end
Hope this can be helpefull to others facing similar issues.

Indeterminate return type of a function

I'm developing a parser of Adobe Type 1 font, using C++ language. And there is a problem when I tried to decode the DICT Data.
The operands in the DICT, which are stored as byte-sequence in the PDF file, may be either integer or real number.
I defined a function, whose prototype is getOperandVal(unsigned char* buf), to decode the sequence to number. And the problem appeared.
Before parse the buf, we can not know the buf is real or integer number. So I can not determine the return-value type, which should be int or double.
A solution is to use a struct as the return-value type. The struct is like below:
typedef struct
{
int interger;
double real;
bool bReal;
}RET;
Then the function prototype is:
RET getOperandVal(unsigned char* buf);
But I think it is not compact. First of all, it is inconvenient to use. Second, the program will run slower when the size of data is big.
Can anyone give me a better solution? Can template do it?
Thank you very much!
Addition:
The program will transfer the operands value into byte-sequence for rewriting into file after edit. Consider the requirement, please.
You can't use templates because you don't know at compile time what type will be returned.
But you can use a union:
struct Int_real {
union {
int integer;
double real;
};
bool is_real;
};
A very good idea is to improve upon it by making it safe (allow access to only the field of the union that is active).
Pretty soon (hopefully), you will be able to use std::any
Template types are evaluated at the compile time, you could not change function prototype dynamically. You could either upscale return value to the biggest size (for example always return double), return a struct or use some variant implementation, like boost::variant.

Switch statement on char variable

A library we are using defines constants and we have:
const char field[] = "666"
and I would like to:
switch(an_int){
case field:
Is there a way to achieve this? I get a compiler error saying field is not usable in a constant expression (GCC 5.2).
I would really wish to avoid modifying the declaration of field if possible.
field is an array. It is not a single value you can switch on.
You're trying to switch on the contents of a character array, when it is interpreted as an integer value.
Use atoi(), or a helper std::istringstream's operator >>, to convert the array into an int variable, then switch on it.
No, It is not possible to have switch statement on char array/string. In case you are sure that the field will contain numeric value then convert char array to integer.

Looking for a MACRO adding two characters together for switch cases

I'm working on an old network engine and the type of package sent over the network is made up of 2 bytes.
This is more or less human readable form, for example "LO" stands for Login.
In the part that reads the data there is an enormous switch, like this:
short sh=(((int)ad.cData[p])<<8)+((int)ad.cData[p+1]);
switch(sh)
{
case CMD('M','D'):
..some code here
break
where CMD is a define:
#define CMD(a,b) ((a<<8)+b)
I know there are better ways but just to clean up a bit and also to be able to search for the tag (say "LO") more easily (and not search for different types of "'L','O'" or "'L' , 'O'" or the occasional "'L', 'O'" <- spaces make it hard to search) I tried to make a MACRO for the switch so I could use "LO" instead of the define but I just can't get it to compile.
So here is the question: how do you change the #define to a macro that I can use like this instead:
case CMD("MD"):
..some code here
break
It started out as a little subtask to make life a little bit easier but now I can't get it out of my head, thanks for any help!
Cheers!
[edit] The code works, it the world that's wrong! ie. Visual Studio 2010 has a bug concerning this. No wonder I cut my teeth on it.
Macro-based solution
A string-literal is really an instance of char const[N] where N is the length of the string, including the terminating null-byte. With this in mind you can easily access any character within the string-literal by using string-literal[idx] to specify that you'd like to read the character stored at offset idx.
#define CMD(str) ((str[0]<<8)+str[1])
CMD("LO") => (("LO"[0]<<8)+"LO"[1]) => (('L'<<8)+'0')
You should however keep in mind that there's nothing preventing your from using the above macro with a string which is shorter than that of length 2, meaning that you can run into undefined-behavior if you try to read an offset which is not actually valid.
RECOMMENDED: C++11, use a constexpr function
You could create a function usable in constant-expressions (and with that, in case-labels), with a parameter of reference to const char[3], which is the "real" type of your string-literal "FO".
constexpr short cmd (char const(&ref)[3]) {
return (ref[0]<<8) + ref[1];
}
int main () {
short data = ...;
switch (data) {
case cmd("LO"):
...
}
}
C++11 and user-defined literals
In C++11 we were granted the possibility to define user-defined literals. This will make your code far easier to maintain and interpret, as well as having it be safer to use:
#include <stdexcept>
constexpr short operator"" _cmd (char const * s, unsigned long len) {
return len != 2 ? throw std::invalid_argument ("") : ((s[0]<<8)+s[1]);
}
int main () {
short data = ...;
switch (data) {
case "LO"_cmd:
...
}
}
The value associated with a case-label must be yield through a constant-expression. It might look like the above might throw an exception during runtime, but since a case-label is constant-expression the compiler must be able to evaluate "LO"_cmd during translation.
If this is not possible, as in "FOO"_cmd, the compiler will issue a diagnostic saying that the code is ill-formed.

how to use strcat with an ENUM?

I have an external tool which is generating an ENUM based on user inputs. Now this ENUM is being used by my C++ code where in i have to select a particular ENUM based on a variable say 'x'. The ENUMS generated are of the form 'ENUM_1', 'ENUM_2', 'ENUM_3'....so on. Now I want the code inside my code such that the appropriate ENUM is chosen based on 'x'. I tried using the strcat function like:
typedef enum ( enum_1, enum_2, enum_3...enum_n) map1;
y=(map1)strcat("enum_", x);
but it gives me the error "Cannot convert from char* to map1.
Can someone pls suggest a method of achieving this.
ThankYou
You can't do this using strcat. From the description what I understand is that you want to convert x to map1. To achieve this, you can do map1 m = (map1)(x-1); See this sample code:
typedef enum { enum_1, enum_2, enum_3} map1;
int main()
{
int x = 1;
map1 m = (map1)(x-1);
}
-1 is required because, the integer value of the enums in map1 starts from 0.
You can't do this. Well you can't do it this way...
Enums aren't evaluated by name at compile time. You'll have to try something with the preprocessor. You can create a define to do something similar. Something like:
#define fn(x) enum_##x
And then call
fn(x)
But this happens when the file gets preprocessed. So you can't access runtime variables. Judging by your code I don't think you'll be able to do what you want.
Good luck though.
Now I want the code inside my code such that the appropriate ENUM is chosen based on 'x'.
Enumerated values are constants and based on the statement I assume that x is an integer data type.
y=(map1)strcat("enum_", x);
strcat(..) passing parameters should be of type char*. And clearly x is not of type char* based on previous statement. It not clear why are you using strcat for achieving this task.
Answer for your subject line: No. You cannot use strcat with enumerated values.