www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Distinguish float and integer types from string

reply Jacob Shtokolov <jacob.100205 gmail.com> writes:
Hi,

Recently, I was trying to solve some funny coding challenges 
(https://www.techgig.com).
The questions were really simple, but I found it interesting 
because the website allows to use D.

One of the task was to take a string from STDIN and detect its 
type.
There were a few options: Float, Integer, string and "something 
else" (which, I think, doesn't have any sense under the scope of 
the task).

Anyway, I was struggling to find a built-in function to 
distinguish float and integer types from a string.

I came to the following solution:

```
import std.stdio;
import std.range;
import std.conv;
import std.string;
import std.format;

immutable msg = "This input is of type %s";

void main()
{
     string type;
     auto data = stdin.byLine.takeOne.front;

     if (data.isNumeric) {
         type = data.indexOf(".") >= 0 ? "Float" : "Integer";
     }
     else {
         type = "string";
     }

     writeln(msg.format(type));
}
```

But I think that's ugly. The thing is that in PHP, for example, I 
would do that like this:

```
if (is_integer($data)) {
     //...do smth
}
else if (is_float($data)) {
     //...do smth
}
else {
     //...do smth
}
```

I tried to use std.conv.to and std.conv.parse, but found that 
they can't really do this. When I call `data.to!int`, the value 
of "123.45" will be converted to int!

Is there any built-in way to detect these types?

Thanks!
Mar 09
next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 9 March 2019 at 18:11:09 UTC, Jacob Shtokolov wrote:w
 One of the task was to take a string from STDIN and detect its 
 type.
The way I'd do this is a very simple loop: enum Type { String, Float, Int } if(str.length && str[0] == '-') { str = str[1 .. $]; } Type type = str.length ? Type.Int : Type.String; foreach(ch; str) { if(ch == '.' && type = Type.Int) type = Type.Float; else if(ch < '0' || ch > '9') { type = Type.String; break; } } And if you need to support other details, add them on top of that. For example, exponents on floats may be a second clause like how I put negative ahead. You may also choose to use a regular expression though I think that is overkill for this.
     if (data.isNumeric) {
There are several caveats on that isNumeric function: it sees if something looks like a D numeric literal, which might not be what you want. For example, isNumeric("1UL") passes because the U and L suffixes are allowed in D literals...
 But I think that's ugly. The thing is that in PHP, for example, 
 I would do that like this:

 ```
 if (is_integer($data)) {
Simiarly, this also will not od what you want. is_integer("1") will return false. "1" is of type string. Those functions check the dynamic type tag, not the contents of a string. (actually, you arguably can just always return "string" cuz stdin is basically just a string or a binary stream anyway :P ) PHP's is_numeric returns true for both integer and floating point things, similarly to D's...
Mar 09
prev sibling next sibling parent spir <denis.spir gmail.com> writes:
On 09/03/2019 19:11, Jacob Shtokolov via Digitalmars-d-learn wrote:
 The thing is that in PHP, for example, I would do
The thing is php needs to be able to "lexify" raw input data at runtime, while in D this is done at compile-time. The ompiler has the lexer to do that. But I agree that, for user input, it would be cool to have such a feature available. However, this would quickly become complex because of (the reciprocal of) localisation, or even personalisation. Eg I like to write decimals like: -1'234'457,098 diniz
Mar 10
prev sibling next sibling parent Soulsbane <paul acheronsoft.com> writes:
On Saturday, 9 March 2019 at 18:11:09 UTC, Jacob Shtokolov wrote:
 Hi,

 Recently, I was trying to solve some funny coding challenges 
 (https://www.techgig.com).
 The questions were really simple, but I found it interesting 
 because the website allows to use D.

 One of the task was to take a string from STDIN and detect its 
 type.
 There were a few options: Float, Integer, string and "something 
 else" (which, I think, doesn't have any sense under the scope 
 of the task).

 Anyway, I was struggling to find a built-in function to 
 distinguish float and integer types from a string.

 I came to the following solution:

 ```
 import std.stdio;
 import std.range;
 import std.conv;
 import std.string;
 import std.format;

 immutable msg = "This input is of type %s";

 void main()
 {
     string type;
     auto data = stdin.byLine.takeOne.front;

     if (data.isNumeric) {
         type = data.indexOf(".") >= 0 ? "Float" : "Integer";
     }
     else {
         type = "string";
     }

     writeln(msg.format(type));
 }
 ```

 But I think that's ugly. The thing is that in PHP, for example, 
 I would do that like this:

 ```
 if (is_integer($data)) {
     //...do smth
 }
 else if (is_float($data)) {
     //...do smth
 }
 else {
     //...do smth
 }
 ```

 I tried to use std.conv.to and std.conv.parse, but found that 
 they can't really do this. When I call `data.to!int`, the value 
 of "123.45" will be converted to int!

 Is there any built-in way to detect these types?

 Thanks!
Unless I'm missing something perhaps two functions like this: bool isInteger(string value) pure nothrow safe { import std.string : isNumeric; return (isNumeric(value) && value.count(".") == 0) ? true : false; } bool isDecimal(string value) pure nothrow safe { import std.string : isNumeric; return (isNumeric(value) && value.count(".") == 1) ? true : false; }
Mar 11
prev sibling next sibling parent Johann Lermer <johann.lermer elvin.eu> writes:
On Saturday, 9 March 2019 at 18:11:09 UTC, Jacob Shtokolov wrote:
 I tried to use std.conv.to and std.conv.parse, but found that 
 they can't really do this. When I call `data.to!int`, the value 
 of "123.45" will be converted to int!
Are you sure? This here works for me: import std.stdio; import std.string; import std.conv; void main () { auto s = readln.strip; try { int i = to!int (s); writefln ("string is an int: %s", i); } catch(Exception e) { try { float f = to!float(s); writefln ("string is a float: %s", f); } catch(Exception e) { writefln ("string is an neither an int nor a float: %s", s); } } }
Mar 11
prev sibling parent reply XavierAP <n3minis-git yahoo.es> writes:
On Saturday, 9 March 2019 at 18:11:09 UTC, Jacob Shtokolov wrote:
 One of the task was to take a string from STDIN and detect its 
 type.
 There were a few options: Float, Integer, string and "something 
 else" (which, I think, doesn't have any sense under the scope 
 of the task).
Another std-based solution I came up with: bool isInteger(string str) { if(str.isNumeric) { try { return str.to!long == str.to!real; } catch(ConvException) { return false; } } else return false; }
 I tried to use std.conv.to and std.conv.parse, but found that 
 they can't really do this. When I call `data.to!int`, the value 
 of "123.45" will be converted to int!
What compiler version are you using? I on the other hand was surprised that I needed the try-catch above, after having already checked isNumeric. The documentation claims that the conversion to int or long would truncate, but my compiler (v2.084.0) throws instead.
Mar 11
parent XavierAP <n3minis-git yahoo.es> writes:
On Monday, 11 March 2019 at 15:03:39 UTC, XavierAP wrote:
 What compiler version are you using? I on the other hand was 
 surprised that I needed the try-catch above, after having 
 already checked isNumeric. The documentation claims that the 
 conversion to int or long would truncate, but my compiler 
 (v2.084.0) throws instead.
Of course now I realize that using try-catch I no longer need to check isNumeric... My design didn't use try-catch but I had to add it because std.conv:to behaves differently from the documentation: https://dlang.org/phobos/std_conv.html#to Not sure if I need to update my DMD, or it's the documentation that's out of date, or something else is wrong.
Mar 11