A LINQ way of converting text containing decimals to int?

R

raylopez99

Refer to Int32.TryParse method: http://msdn.microsoft.com/en-us/library/zf50za27.aspx
if you have to, specifically this example:

numericString = "10345.72"
styles = NumberStyles.Integer Or NumberStyles.AllowDecimalPoint
CallTryParse(numericString, styles)

Which failed to convert the string "10345.72" to the int 10345,
because of the extra digits after the "."

My question is this: is there a neat "LINQ" type way of parsing such
a string so that the first time a "." (period) is found, the string is
extracted, and then I can use Int32.TryParse?

I know I can solve this problem using a character buffer, reading each
Unicode byte into the buffer, then stopping the first time I find a
".", then reading out the buffer to create a string, then using
Int32.TryParse to extract the int from the string. That is, perhaps I
can use the StringBuilder method to CopyTo a char array, then use a
trick to extract the numeric string before the "."

For example--

StringBuilder sb = new StringBuilder ("10345.72");
int count = sb.Length;

char[] temporary_charBuf1 = new char[100]; // 1 of 2

sb.Copy(0,temporary_charBuf1,0,count);

char[] charBuf2 = new char [100] //2 of 2

foreach (char c in temporary_charBuf) {//code here: if char is not a
period, fill charBuf2, otherwise not and break once a period is found}

string numericString = "";

numericString = new string(charBuf2); // Create new string passing
charBuf2 into the constructor

Now your numericString should be 10345 from the original string
"10345.72".

But I'm looking for a faster or shorter way (since this is not a big
deal, and I don't want to spend too many lines of code making it
work). As you can see from the above, which does not even include the
code inside the foreach loop, it's a lot of code.

Can we replace this with one line of LINQ (plus I'm trying to learn
LINQ as I go)?
No big deal (pseudo code is OK)...just curious.

RL
 
J

Jon Skeet [C# MVP]

Can we replace this with one line of LINQ (plus I'm trying to learn
LINQ as I go)?
No big deal (pseudo code is OK)...just curious.

You *could* do it with LINQ, but it would be painfully slow and
unreadable. Here's a simpler method to do it:

public int ParseInt32BeforePeriod(string text)
{
int periodIndex = text.IndexOf('.');
if (periodIndex != -1)
{
text = text.Substring(0, periodIndex);
}
return int.Parse(text);
}

(You can turn it into a TryParseInt32BeforePeriod taking an out
parameter and returning a boolean pretty easily, if you want.)
 
A

Alun Harford

raylopez99 said:
Refer to Int32.TryParse method: http://msdn.microsoft.com/en-us/library/zf50za27.aspx
if you have to, specifically this example:

numericString = "10345.72"
styles = NumberStyles.Integer Or NumberStyles.AllowDecimalPoint
CallTryParse(numericString, styles)

Which failed to convert the string "10345.72" to the int 10345,
because of the extra digits after the "."

My question is this: is there a neat "LINQ" type way of parsing such
a string so that the first time a "." (period) is found, the string is
extracted, and then I can use Int32.TryParse?

int result = (int)Math.Floor(decimal.Parse("10345.72"));

Alun Harford
 
R

raylopez99

Jon said:
(You can turn it into a TryParseInt32BeforePeriod taking an out
parameter and returning a boolean pretty easily, if you want.)

Yes, please, I want. If you have a moment, as a learning exercise for
me it would be helpful. Just the other day in fact I did not realize
that with ref 'out' parameter you don't need to initialize the 'out'
parameter, it just magically shows up, if at all, when the function
runs, so it would be helpful to see another example of this.

BTW I did try the char[] to string conversion mentioned in the
original post and it worked, here is the format.

char[] charBuf; string hiString;
public myForm() {
InitializeComponent();
StringBuilder sb = new StringBuilder("hi there!"); //what
is to be converted to char
int count0 = sb.Length;
charBuf = new char[count0]; // char array, holds chars
‘h,i, , t,h,e,r,e,!’
//can be any size big enough, but if you make it too big it gets
filled with blanks anyway
sb.CopyTo(0, charBuf, 0, count0);
hiString = new string(charBuf); //should be string "hi
there!; Yes, works.
}
 
J

Jon Skeet [C# MVP]

Yes, please, I want.  If you have a moment, as a learning exercise for
me it would be helpful.

public bool ParseInt32BeforePeriod(string text, out value)
{
int periodIndex = text.IndexOf('.');
if (periodIndex != -1)
{
text = text.Substring(0, periodIndex);
}
return int.TryParse(text, out value);
}

BTW I did try the char[] to string conversion mentioned in the
original post and it worked, here is the format.

You may be interested to know that the String.ToCharArray() method
does the same thing.

Jon
 
J

Jon Skeet [C# MVP]

Cripes, is that legal?  My gawd, it is.  That's brilliant.

Out of interest, which bit did you expect to be illegal?

It will work with non-negative decimals, but would fail for either
"-3.4" (returning -4) or "3.wibble". These may not be a problem for
you, of course, but it's worth being aware of them.

Jon
 
A

Alun Harford

Jon said:
Out of interest, which bit did you expect to be illegal?

It will work with non-negative decimals, but would fail for either
"-3.4" (returning -4) or "3.wibble". These may not be a problem for
you, of course, but it's worth being aware of them.

Good point.

How about:

int result = int.Parse(
new string("10345.72".ToCharArray().TakeWhile(c => c != '.')
.ToArray()));

Alun Harford
 
J

Jon Skeet [C# MVP]

Alun Harford said:
Good point.

How about:

int result = int.Parse(
new string("10345.72".ToCharArray().TakeWhile(c => c != '.')
.ToArray()));

Yup, that's about what I'd come up with if we were absolutely
*desperate* for a LINQ solution - although as String implements
IEnumerable<char> already, there's no need to call ToCharArray. It's
pretty icky though :)
 
R

raylopez99

public bool ParseInt32BeforePeriod(string text, out value)
{
    int periodIndex = text.IndexOf('.');
    if (periodIndex != -1)
    {
        text = text.Substring(0, periodIndex);
    }
    return int.TryParse(text, out value);

}

<snip>

public bool ParseInt32BeforePeriod(string text, out value) //
<--compiler says an error here
{
int periodIndex = text.IndexOf('.');
if (periodIndex != -1)
{
text = text.Substring(0, periodIndex);
}
return int.TryParse(text, out value);
}

This failed to compile: "error CS1001: Identifier expected" and it
points to the outer parens at the arrow above. Any idea why?

Also, how do you actually use this in main()? is it something like:

anObject myObject = new anObject();
int myint;
if (myObject.ParseInt32BeforePeriod("12345.54", value){ myint =
value;} //??

RL
 
J

Jon Skeet [C# MVP]

raylopez99 said:
public bool ParseInt32BeforePeriod(string text, out value) //
<--compiler says an error here

Sorry, "out int value".

That's what I get for not compiling the app. (I was writing that post
on the train, on a pretty weak laptop which takes a while to do
anything...)
This failed to compile: "error CS1001: Identifier expected" and it
points to the outer parens at the arrow above. Any idea why?

Yup, it thinks that "value" of the
Also, how do you actually use this in main()? is it something like:

anObject myObject = new anObject();
int myint;
if (myObject.ParseInt32BeforePeriod("12345.54", value){ myint =
value;} //??

You'd do:

anObject myObject = new anObject(); // Or just make it a static method
int myInt;
if (myObject.ParseInt32BeforePeriod("12345.54", out myInt))
{
// Use myInt here
}

If you look at P131-133 of C# in Depth you'll find an alternative way
of representing this.
 
R

raylopez99

You'd do:

anObject myObject = new anObject(); // Or just make it a static method
int myInt;
if (myObject.ParseInt32BeforePeriod("12345.54", out myInt))
{
    // Use myInt here

}

Just compiled it, and it works perfectly. Thanks. Into my form
library it goes for future reference, might even warrant a hardcopy
for the binder...done.
If you look at P131-133 of C# in Depth you'll find an alternative way
of representing this.

OK, but I'm only up to page 34.

Good night and good fight (I'm a couple of hours ahead of you... 1:30
AM here)

RL
 
A

Arne Vajhøj

Alun said:
int result = (int)Math.Floor(decimal.Parse("10345.72"));

Math.Floor should not be necessary.

int result = (int)decimal.Parse("10345.72");

Arne
 
A

Arne Vajhøj

Jon said:
You *could* do it with LINQ, but it would be painfully slow and
unreadable. Here's a simpler method to do it:

public int ParseInt32BeforePeriod(string text)
{
int periodIndex = text.IndexOf('.');
if (periodIndex != -1)
{
text = text.Substring(0, periodIndex);
}
return int.Parse(text);
}

(You can turn it into a TryParseInt32BeforePeriod taking an out
parameter and returning a boolean pretty easily, if you want.)

IndexOf and Substring reminds me too much of strstr and strncpy.
And it is pretty well camouflaged culture invariant !

Either Alan's (int)decimal.Parse(s) or a regex like
int.Parse(Regex.Match(s, @"\d+").Value) would be better
in my opinion.

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top