-2

I have two regexes took from here: https://stackoverflow.com/a/26119160/2829150 It should correctly validate both latitude and longitude. Nevertheless something is wrong, and for valid coordinates it gives me false.

Example (valid) coordinates which is till got as it is not valid according to methods regex.

Lat: 53.0102721
Lon: 18.6048094

Code:

public static bool IsValidLatitude(string latitude)
{
      var reg = new Regex(@"^(\+|-)?((\d((\.)|\.\d{1,6})?)|(0*?[0-8]\d((\.)|\.\d{1,6})?)|(0*?90((\.)|\.0{1,6})?))$");
      return reg.IsMatch(latitude);
}

public static bool IsValidLongitude(string longtitude)
{
      var reg = new Regex(@"^(\+|-)?((\d((\.)|\.\d{1,6})?)|(0*?\d\d((\.)|\.\d{1,6})?)|(0*?1[0-7]\d((\.)|\.\d{1,6})?)|(0*?180((\.)|\.0{1,6})?))$");
      return reg.IsMatch(longtitude);
}

Note that: it don't need to be regex. It can be whatever else keeping in mind to check whether dot (.) was used no matter to what pc settings for separator is set up. I am open on any other proposition.

Arie
  • 3,041
  • 7
  • 32
  • 63
  • `d{1,6}` matches 1-6 digits and `53.0102721` has 7 digits after the dot. – The fourth bird Sep 29 '20 at 10:12
  • @Thefourthbird so means regex is not correct or? – Arie Sep 29 '20 at 10:13
  • 4
    Much easier instead of complicated regex: use `decimal.TryParse` to parse the string, and verify the result is between -90 and 90 or -180 and 180. – jeroenh Sep 29 '20 at 10:15
  • 1
    Why are you using Regex and not a numeric type? – Johnathan Barclay Sep 29 '20 at 10:15
  • @JohnathanBarclay don;t know i am not regex expert just took it from original post – Arie Sep 29 '20 at 10:16
  • @jeroenh Can you post proposition as full answer. Keeping in mind i have to save it in database with dot (.) not any other related to pc settings but according what i do know decimal.TryParse will pass system separator. In this case regex is better it guaranty dot (.) is used. – Arie Sep 29 '20 at 10:17
  • @Arie The pattern tries several alternatives and matches 1-6 digits and your example data has 7 digits after the dot. I can not say that the pattern by itself is not correct, but it does not match your data. I think the other suggestions in the comment would be an easier approach. – The fourth bird Sep 29 '20 at 10:19

2 Answers2

3

It would be simpler to parse to double then validate:

public static bool IsValidLatitude(string latitude)
    => double.TryParse(latitude, out var l) && -90 <= l && l <= 90;

public static bool IsValidLongitude(string longitude)
    => double.TryParse(longitude, out var l) && -180 <= l && l <= 180;

To force . as the decimal separator, you could use an overload of double.TryParse that allows CultureInfo.InvariantCultute to be used:

public static bool IsValidLatitude(string latitude)
    => double.TryParse(latitude, NumberStyles.Float, CultureInfo.InvariantCultute, out var l)
        && -90 <= l && l <= 90;

public static bool IsValidLongitude(string longitude)
    => double.TryParse(longitude, NumberStyles.Float, CultureInfo.InvariantCultute, out var l)
        && -180 <= l && l <= 180;
Johnathan Barclay
  • 18,599
  • 1
  • 22
  • 35
  • Can you modify to make sure (.) dot is used ? – Arie Sep 29 '20 at 10:20
  • `double` is a floating-point type, so includes decimal places. – Johnathan Barclay Sep 29 '20 at 10:20
  • Yes, what i ment is : if user's pc decimal separator is set to e.g comma (,) i don't want such coordinate to be treated as valid. – Arie Sep 29 '20 at 10:21
  • Would it mean if any other separator than dot (.) comes into your methods even if coordinates are valid it will return false ? – Arie Sep 29 '20 at 10:42
  • Yes, `CultureInfo.InvariantCulture` sets the [`NumberDecimalSeparator`](https://learn.microsoft.com/en-us/dotnet/api/system.globalization.numberformatinfo.numberdecimalseparator) to `.`, so only `.` is a valid separator. – Johnathan Barclay Sep 29 '20 at 10:48
  • I thoughtdiffrent that the option: CultureInfo.InvariantCultute will make a check nevermind to user's culture, means if user either has dot or comma in system as decimal separator that function will work, but without that option (CultureInfo.InvariantCultute) if user type separator that is <> system settings method will not work (get false. – Arie Sep 29 '20 at 10:50
  • 1
    Not so: https://dotnetfiddle.net/2t9Bkk – Johnathan Barclay Sep 29 '20 at 10:52
  • 1
    [`CultureInfo.InvariantCulture`](https://learn.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo.invariantculture): "_The invariant culture is culture-insensitive_". – Johnathan Barclay Sep 29 '20 at 10:56
  • ok so simply saying doesn't matter what pc settings are set for decimal separator. In this way means with CultureInfo.InvariantCulture those methods will return true only when coordinate is valid and separator is dot (.) ? – Arie Sep 29 '20 at 10:58
  • 1
    @Arie Yes, the only thing to note is that `NumberStyles.Float` allows trailing and leading whitespace, which may or may not be a problem. If it is, replace that with `NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint`. – Johnathan Barclay Sep 29 '20 at 11:06
  • you mean if values comes to args of methods with leading/trainiling spaces? If so we just could make Trim on incomming arguments values as well? Or its better as you said to replace NumberStyles.Float to NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint ? – Arie Sep 29 '20 at 11:13
  • 1
    `NumberStyles.Float` will trim anyway. If this is not valid, use `NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint`. – Johnathan Barclay Sep 29 '20 at 11:48
2

A much easier way to validate coordinates is to parse the string to a numeric value, and verify it is between -90 and 90 (latitude) and -180 and 180 (longitude):

string latitudeString = "53.0102721";
string longitudeString = "18.6048094";

        bool latitudeIsValid = decimal.TryParse(latitudeString, NumberStyles.AllowDecimalPoint|NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out var latitude) 
                              && Math.Abs(latitude) < 90);
        bool longitudeIsValid = decimal.TryParse(longitudeString, NumberStyles.AllowDecimalPoint|NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out var longitude) 
                              && Math.Abs(longitude) < 180);

As per your requirement to save as a string using . as a decimal separator: first, I would advise to use a numeric data type in your storage system (if possible). If you must store as a string, you can use the original string, or use decimal.ToString with a correct culture and format specifier:

string latitudeAsString = latitude.ToString("N7", CultureInfo.InvariantCulture);    
jeroenh
  • 26,362
  • 10
  • 73
  • 104
  • Can you modify to make sure (.) dot is used ? – Arie Sep 29 '20 at 10:20
  • 2
    Why are you storing this data as a string? Better to use a decimal or floating point type. The decimal separator is just a representation. – jeroenh Sep 29 '20 at 10:26
  • can youn tell me whats N7? – Arie Sep 29 '20 at 10:27
  • https://stackoverflow.com/questions/3966430/format-a-number-with-x-decimal-places-and-invariantculture – jeroenh Sep 29 '20 at 10:28
  • So it means your code will change delimeter to dot(.) if any other delimeter will be returned according to user's settings or it will keep dot(.) if its already there, am i right? – Arie Sep 29 '20 at 10:30
  • @Arie, this is going to a totally different question. You will find a whole lot more information elsewhere, for example in the documentation on formatting of types: https://learn.microsoft.com/en-us/dotnet/standard/base-types/formatting-types – jeroenh Sep 29 '20 at 10:34
  • P.S YOu fot error in your code at Math.Abs(longitude) cannot convert from string to decimal. P.S Why decimal and not double? – Arie Sep 29 '20 at 10:35
  • 1
    decimal has greater precision, but double would also work fine for this case – jeroenh Sep 29 '20 at 10:36
  • at this line i get: latitude.ToString("N7", CultureInfo.InvariantCulture); No overload for method 'ToString' takes 2 arguments – Arie Sep 29 '20 at 10:41
  • `NumberStyles.AllowDecimalPoint` doesn't allow negative numbers. – Johnathan Barclay Sep 29 '20 at 10:51