I'm trying to convert a string representing a double from invariant culture to a double in current culture representation, I'm concerned with how to get the new double representation to use the current number decimal separator of Current Culture.
I used the code below for the conversion :
public static double ConvertToDouble(this object inputVal, bool useCurrentCulture = false)
{
string currentSep = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
string invariantSep = CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator;
if (inputVal.GetType() == typeof(string))
{
if (!currentSep.Equals(invariantSep))
{
inputVal = (inputVal as string).Replace(invariantSep, currentSep);
}
}
if (useCurrentCulture)
return Convert.ToDouble(inputVal, CultureInfo.CurrentCulture);
else
return Convert.ToDouble(inputVal);
}
But the above code always gives me a double with ".", although I use the CurrentCulture for example French supposed to give me a double with comma (",").
Many thanks in advance for any hint.
FreeDev
But the above code always gives me a double with "." as the NumberDecimalSeparator
No, it returns a double. A double is just a number. It doesn't have a NumberDecimalSeparator... only a culture does, and that's only applied when converting to or from strings. Talking about the separator for a double is like talking about whether an int is in decimal or hex - there's no such concept. 0x10 and 16 are the same value, represented by the same bits.
It's not really clear what you're trying to do, but it's crucial to understand the difference between what's present in a textual representation, and what's inherent to the data value itself. You should care about the separator when parsing or formatting - but after you've parsed to a double, that information is gone.
From the comments and your question i guess that you actually want to convert a string to a double with either InvariantCulture or current-culture. This double should then be converted to a string which is formatted by the current-culture datetime-format informations(like NumberDecimalSeparator).
So this method should do two things:
parse string to double
convert double to string
public static string ConvertToFormattedDouble(this string inputVal, IFormatProvider sourceFormatProvider = null, IFormatProvider targetFormatProvider = null)
{
if (sourceFormatProvider == null) sourceFormatProvider = NumberFormatInfo.InvariantInfo;
if (targetFormatProvider == null) targetFormatProvider = NumberFormatInfo.CurrentInfo;
if (sourceFormatProvider == targetFormatProvider)
return inputVal; // or exception?
double d;
bool isConvertable = double.TryParse(inputVal, NumberStyles.Any, sourceFormatProvider, out d);
if (isConvertable)
return d.ToString(targetFormatProvider);
else
return null; // or whatever
}
You can use it in this way:
string input = "1234.567";
string output = input.ConvertToFormattedDouble(); // "1234,567"
Note that i've extended string instead of object. Extensions for object are a bad idea in my opinion. You pollute intellisense with a method that you 'll almost never use (although it applies also to string).
Update:
If you really want to go down this road and use an extension for object that supports any kind of numbers as (boxed) objects or strings you could try this extension:
public static string ConvertToFormattedDouble(this object inputVal, IFormatProvider sourceFormatProvider = null, IFormatProvider targetFormatProvider = null)
{
if (sourceFormatProvider == null) sourceFormatProvider = NumberFormatInfo.InvariantInfo;
if (targetFormatProvider == null) targetFormatProvider = NumberFormatInfo.CurrentInfo;
if (inputVal is string)
{
double d;
bool isConvertable = double.TryParse((string)inputVal, NumberStyles.Any, sourceFormatProvider, out d);
if (isConvertable)
return d.ToString(targetFormatProvider);
else
return null;
}
else if (IsNumber(inputVal))
{
decimal d = Convert.ToDecimal(inputVal, sourceFormatProvider);
return Decimal.ToDouble(d).ToString(targetFormatProvider);
}
else
return null;
}
public static bool IsNumber(this object value)
{
return value is sbyte
|| value is byte
|| value is short
|| value is ushort
|| value is int
|| value is uint
|| value is long
|| value is ulong
|| value is float
|| value is double
|| value is decimal;
}
Usage:
object input = 1234.56745765677656578d;
string output = input.ConvertToFormattedDouble(); // "1234,56745765678"
Related
I have this data:
AC level : FAIL
ADC AC - 0x0440
AC level : FAIL
Average ADC Batt - 0x733e
I want to get the Adc Ac value for example the 0x0440 but when I want to store it in the database ,the output will display 0x737eBatt Level : MidADC but it happened intermittently.
Here is my code:
public static string getBetween(string strSource, string strStart, string strEnd)
{
if (strSource.Contains(strStart) && strSource.Contains(strEnd))
{
int Start, End;
Start = strSource.IndexOf(strStart, 1) + strStart.Length;
End = strSource.IndexOf(strEnd, Start);
return strSource.Substring(Start, End - Start);
}
return "";
}
// Find ADC value
string ADC = getBetween(serialdata, "-", "AC");
You should probably try to extract the values by their key, rather than relying on characters before and after. In your example the string "AC" already appears twice before the text that you are interested in. Try a function like the following, to get any value:
static bool TryGetValue(string serialData, string key, out string value)
{
var m = Regex.Match(serialData, $".*{Regex.Escape(key)}\\s*[-:](?<value>.*)$", RegexOptions.Multiline);
value = m.Groups["value"].Value.Trim();
return m.Success;
}
you'd call it like this:
if (TryGetValue(serialData, "ADC AC", out var value))
{
Console.WriteLine(value);
}
I have a string coming from PC through serial to a microcontroller (Arduino), e.g.:
"HDD: 55 - CPU: 12.6 - Weather: Cloudy [...] $";
by this function I found:
String inputStringPC = "";
boolean stringCompletePC = false;
void serialEvent() {
while (Serial.available()) {
char inChar = (char)Serial.read();
inputStringPC += inChar;
if (inChar == '$') // end marker of the string
{
stringCompletePC = true;
}
}
}
I would like to extract the first number of it after the word HDD, CPU and also get the string after Weather (ie "cloudy"); my thinking is something like that:
int HDD = <function that does that>(Keyword HDD);
double CPU = <function that does that>(Keyword CPU);
char Weather[] = <function that does that>(Keyword Weather);
What is the right function to do that?
I looked into inputStringSerial.indexOf("HDD") but I am still a learner to properly understand what it does and don't know if theres a better function.
My approach yielded some syntax errors and confused me with the difference in usage between "String inputStringSerial" (class?) and "char inputStringSerial[]" (variable?). When I do 'string inputStringSerial = "";' PlatformIO complains that "string" is undefined. Any help to understand its usage here is greatly appreciated.
Thanks a bunch.
The String class provides member functions to search and copy the contents of the String. That class and all its member functions are documented in the Arduino Reference:
https://www.arduino.cc/reference/tr/language/variables/data-types/stringobject/
The other way a list of characters can be represented is a char array, confusingly also called a string or cstring. The functions to search and copy the contents of a char array are documented at
http://www.cplusplus.com/reference/cstring/
Here is a simple Sketch that copies and prints the value of the Weather field using a String object. Use this same pattern - with different head and terminator values - to copy the string values of the other fields.
Once you have the string values of HDD and CPU, you'll need to call functions to convert those string values into int and float values. See the String member functions toInt() and toFloat() at
https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/toint/
or the char array functions atoi() and atof() at
http://www.cplusplus.com/reference/cstdlib/atoi/?kw=atoi
String inputStringPC = "HDD: 55 - CPU: 12.6 - Weather: Cloudy [...] $";
const char headWeather[] = "Weather: "; // the prefix of the weather value
const char dashTerminator[] = " -"; // one possible suffix of a value
const char dollarTerminator[] = " $"; // the other possible suffix of a value
void setup() {
int firstIndex; // index into inputStringPC of the first char of the value
int lastIndex; // index just past the last character of the value
Serial.begin(9600);
// find the Weather field and copy its string value.
// Use similar code to copy the values of the other fields.
// NOTE: This code contains no error checking for unexpected input values.
firstIndex = inputStringPC.indexOf(headWeather);
firstIndex += strlen(headWeather); // firstIndex is now the index of the char just past the head.
lastIndex = inputStringPC.indexOf(dollarTerminator, firstIndex);
String value = inputStringPC.substring(firstIndex, lastIndex);
Serial.print("Weather value = '");
Serial.print(value);
Serial.println("'");
}
void loop() {
// put your main code here, to run repeatedly:
}
When run on an Arduio Uno, this Sketch produces:
Weather value = 'Cloudy [...]'
See the method below [Not Working as expected].I want double or int as method parameters and return as any data type [in my case return as int,double or string].
Requirement:
if the double or int value is zero then return an empty string else the real int or double value. I don't want to use dynamic as return type
private static T CheckZero<T>( dynamic val ) {
return Math.Sign(val) == 0 ? (T)Convert.ChangeType(string.Empty, typeof(string)) : val;
}
I would like to parse strings like 1 or 32.23 into integers and doubles. How can I do this with Dart?
You can parse a string into an integer with int.parse(). For example:
var myInt = int.parse('12345');
assert(myInt is int);
print(myInt); // 12345
Note that int.parse() accepts 0x prefixed strings. Otherwise the input is treated as base-10.
You can parse a string into a double with double.parse(). For example:
var myDouble = double.parse('123.45');
assert(myDouble is double);
print(myDouble); // 123.45
parse() will throw FormatException if it cannot parse the input.
In Dart 2 int.tryParse is available.
It returns null for invalid inputs instead of throwing. You can use it like this:
int val = int.tryParse(text) ?? defaultValue;
Convert String to Int
var myInt = int.parse('12345');
assert(myInt is int);
print(myInt); // 12345
print(myInt.runtimeType);
Convert String to Double
var myDouble = double.parse('123.45');
assert(myInt is double);
print(myDouble); // 123.45
print(myDouble.runtimeType);
Example in DartPad
As per dart 2.6
The optional onError parameter of int.parse is deprecated. Therefore, you should use int.tryParse instead.
Note:
The same applies to double.parse. Therefore, use double.tryParse instead.
/**
* ...
*
* The [onError] parameter is deprecated and will be removed.
* Instead of `int.parse(string, onError: (string) => ...)`,
* you should use `int.tryParse(string) ?? (...)`.
*
* ...
*/
external static int parse(String source, {int radix, #deprecated int onError(String source)});
The difference is that int.tryParse returns null if the source string is invalid.
/**
* Parse [source] as a, possibly signed, integer literal and return its value.
*
* Like [parse] except that this function returns `null` where a
* similar call to [parse] would throw a [FormatException],
* and the [source] must still not be `null`.
*/
external static int tryParse(String source, {int radix});
So, in your case it should look like:
// Valid source value
int parsedValue1 = int.tryParse('12345');
print(parsedValue1); // 12345
// Error handling
int parsedValue2 = int.tryParse('');
if (parsedValue2 == null) {
print(parsedValue2); // null
//
// handle the error here ...
//
}
void main(){
var x = "4";
int number = int.parse(x);//STRING to INT
var y = "4.6";
double doubleNum = double.parse(y);//STRING to DOUBLE
var z = 55;
String myStr = z.toString();//INT to STRING
}
int.parse() and double.parse() can throw an error when it couldn't parse the String
Above solutions will not work for String like:
String str = '123 km';
So, the answer in a single line, that works in every situation for me will be:
int r = int.tryParse(str.replaceAll(RegExp(r'[^0-9]'), '')) ?? defaultValue;
or
int? r = int.tryParse(str.replaceAll(RegExp(r'[^0-9]'), ''));
But be warned that it will not work for the below kind of string
String problemString = 'I am a fraction 123.45';
String moreProblem = '20 and 30 is friend';
If you want to extract double which will work in every kind then use:
double d = double.tryParse(str.replaceAll(RegExp(r'[^0-9\.]'), '')) ?? defaultValue;
or
double? d = double.tryParse(str.replaceAll(RegExp(r'[^0-9\.]'), ''));
This will work for problemString but not for moreProblem.
you can parse string with int.parse('your string value');.
Example:- int num = int.parse('110011'); print(num); // prints 110011 ;
If you don't know whether your type is string or int you can do like this:
int parseInt(dynamic s){
if(s.runtimeType==String) return int.parse(s);
return s as int;
}
For double:
double parseDouble(dynamic s){
if(s.runtimeType==String) return double.parse(s);
return s as double;
}
Therefore you can do parseInt('1') or parseInt(1)
void main(){
String myString ='111';
int data = int.parse(myString);
print(data);
}
String age = stdin.readLineSync()!; // first take the input from user in string form
int.parse(age); // then parse it to integer that's it
You can do this for easy conversion like this
Example Code Here
void main() {
var myInt = int.parse('12345');
var number = myInt.toInt();
print(number); // 12345
print(number.runtimeType); // int
var myDouble = double.parse('123.45');
var double_int = myDouble.toDouble();
print(double_int); // 123.45
print(double_int.runtimeType);
}
Looking for either a solution, some ideas or being point in the right direction on how to resolve a problem.
Basically, I have to figure out if a string value is in between a Low and High string value. However, the values are in a format which String.Compare will not work. But, a human can easily figure out.
For example, one of my ranges is Low: A7, High A12. A8 fits in between those values but String.Compare says it does not. A13 would not fit between the values.
Other examples of Low and High values are:
Low Value - High Value
1A1 - 1A12
25W00 - 25W050
42W1 - 42W296
W232N0002 - W232N000598
In the above examples 1A2 would fit between the Low High Value of 1A1 and 1A12, but 1A100 would not.
Any ideas on how to resolve this? I know this had to have been encountered before.
This could use some optimization, but it's a proof of concept.
Just convert the letters to numerical values and compare the results:
private bool ValueIsBetween(string value, string lowValue, string highValue)
{
long low = long.Parse(ConvertToNumber(lowValue));
long high = long.Parse(ConvertToNumber(highValue));
long val = long.Parse(ConvertToNumber(value));
return val > low && val < high;
}
private string ConvertToNumber(string value)
{
value = value.ToUpper();
value = value.Replace("A", "0");
value = value.Replace("B", "1");
value = value.Replace("C", "2");
value = value.Replace("D", "3");
value = value.Replace("E", "4");
value = value.Replace("F", "5");
value = value.Replace("G", "6");
value = value.Replace("H", "7");
value = value.Replace("I", "8");
value = value.Replace("J", "9");
value = value.Replace("K", "10");
value = value.Replace("L", "11");
value = value.Replace("M", "12");
value = value.Replace("N", "13");
value = value.Replace("O", "14");
value = value.Replace("P", "15");
value = value.Replace("Q", "16");
value = value.Replace("R", "17");
value = value.Replace("S", "18");
value = value.Replace("T", "19");
value = value.Replace("U", "20");
value = value.Replace("V", "21");
value = value.Replace("W", "22");
value = value.Replace("X", "23");
value = value.Replace("Y", "24");
value = value.Replace("Z", "25");
return value;
}
Results:
ValueIsBetween("1A2", "1A1", "1A12");
true
ValueIsBetween("1A100", "1A1", "1A12");
false
ValueIsBetween("43W4", "42W1", "44W3");
true
Edit:
Try this improved algorithm instead:
private bool ValueIsBetween(string value, string lowValue, string highValue)
{
return !ValueIsLessThan(value, lowValue) && ValueIsLessThan(value, highValue);
}
private bool ValueIsLessThan(string value, string compareTo)
{
var matches = Regex.Matches(value, "[0-9]+|[a-zA-Z]+");
var matchesB = Regex.Matches(compareTo, "[0-9]+|[a-zA-Z]+");
var count = matches.Count < matchesB.Count ? matches.Count : matchesB.Count;
for (int i = 0; i < count; i++)
{
long val;
long val2;
if (long.TryParse(matches[i].Value, out val))
{
if (long.TryParse(matchesB[i].Value, out val2))
{
if (val > val2) return false;
if (val < val2) return true;
}
else
{
return false;
}
}
else
{
if (matches[i].Value.CompareTo(matchesB[i].Value) > 0 ) return false;
if (matches[i].Value.CompareTo(matchesB[i].Value) < 0 ) return true;
}
}
return true;
}
Results:
ValueIsBetween("B431Z543", "A0", "Z9");
true
ValueIsBetween("4B31Z543", "A0", "Z9");
false
ValueIsBetween("1A2", "1A1", "1A12");
true
ValueIsBetween("1A100", "1A1", "1A12");
false
ValueIsBetween("43W4", "42W1", "44W3");
true
ValueIsBetween("W5", "CC4", "CC6");
false
ValueIsBetween("W8B4", "W5C3", "W7C3");
false
ValueIsBetween("W5C4", "W5C3", "C7W3");
false
Build a class, probably abstract, with sub classes for each pattern.
The pattern for "25W00" could be ^(?<LEFTTHING>.{2})(?<MIDDLETHING>.{1})(?<RIGHTTHING>.{2})$
In your class, capture each Regex group as a string or numeric as appropriate.
I suppose you could come up with some conventions so you might even be able to have a single Type - and pass in that pattern to the constructor.
You may even have some kind of really smart class where you pass in two strings and a common pattern. This super class builds appropriate "comparable" classes (as per above) and returns a boolean result of the comparison. Your client code would be very clean in this case.
Assuming the non-numeric parts are fixed (i.e. you aren't searching for 1B1 being between 1A1 and 1C1), you could use a regex to expand the numerical values to a certain fixed width, so you could then compare the strings.
For example, using
static Regex digits = new Regex(#"\d+");
static string ExpandDigits(string s)
{
return digits.Replace(s, m => string.Format("{0:D10}", int.Parse(m.ToString())));
}
then calling ExpandDigits("W232N0002") yields W0000000232N0000000002.
You could have a comparison method like this:
static bool IsInRange(string lower, string upper, string test)
{
test = ExpandDigits(test);
lower = ExpandDigits(lower);
if (lower.CompareTo(test) <= 0)
{
upper = ExpandDigits(upper);
if (test.CompareTo(upper) <= 0)
{
return true;
}
}
return false;
}