Bug? Regex behaving differently in Java/B4A

alwaysbusy

Expert
Licensed User
Longtime User
When I use the regex from b4a I get the following error on the pattern:

B4X:
java.util.regex.PatternSyntaxException: In a character range [x-y], x is greater than y near index 10:
geo:([\\-0-9.]+),([\\-0-9.]+)(?:,([\\-0-9.]+))?(?:\\?(.*))?
          ^
    at java.util.regex.Pattern.compileImpl(Native Method)
    at java.util.regex.Pattern.compile(Pattern.java:407)
    at java.util.regex.Pattern.<init>(Pattern.java:390)
    at java.util.regex.Pattern.compile(Pattern.java:374)
    at anywheresoftware.b4a.keywords.Regex.getPattern(Regex.java:34)
    at anywheresoftware.b4a.keywords.Regex.Matcher2(Regex.java:97)
    at com.ab.regextest.main._isgeo(main.java:394)
    at com.ab.regextest.main._activity_create(main.java:309)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:170)
    at com.ab.regextest.main.afterFirstLayout(main.java:98)
    at com.ab.regextest.main.access$100(main.java:16)
    at com.ab.regextest.main$WaitForLayout.run(main.java:76)
    at android.os.Handler.handleCallback(Handler.java:730)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:5419)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
    at dalvik.system.NativeStart.main(Native Method)

However, when I use the same pattern in a java library, everything works fine.

Here is the B4A code:
B4X:
Private Sub IsGEO(FoundBC As String) As Boolean
    Dim raw As String = FoundBC
    Dim res As clsResult
    res.Initialize(0)
    'FoundBC = "geo:50.847632,2.860613"
    Dim m As Matcher = Regex.Matcher2("geo:([\\-0-9.]+),([\\-0-9.]+)(?:,([\\-0-9.]+))?(?:\\?(.*))?",Regex.CASE_INSENSITIVE, raw)
    If m.Find = False Then
        Return False
    End If
    res.geoQuery = m.Group(4)
    Try
        res.geoLatitude = m.Group(1)
        If res.geoLatitude > 90 OR res.geoLatitude < -90 Then
            Return False
        End If
        res.geoLongitude = m.Group(2)
        If res.geoLongitude > 180 OR res.geoLongitude < -180 Then
            Return False
        End If
        If m.Group(3) <> "" Then
            res.geoAltitude = m.Group(3)
            If res.geoAltitude < 0 Then
                Return False
            End If
        End If
       
        res.geoURI = "geo:" & res.geoLatitude & "," & res.geoLongitude
        If res.geoAltitude > 0 Then
            res.geoURI = res.geoURI & "," & res.geoAltitude
        End If
        If res.geoQuery <> "" Then
            res.geoURI = res.geoURI & "?" & res.geoQuery
        End If
        res.resType = res.TYPE_GEO
        Return True
    Catch
        Return False
    End Try
End Sub

And here is the java code:
B4X:
private static final Pattern GEO_URL_PATTERN =
      Pattern.compile("geo:([\\-0-9.]+),([\\-0-9.]+)(?:,([\\-0-9.]+))?(?:\\?(.*))?", Pattern.CASE_INSENSITIVE);

public boolean IsGeo(String result) {
            CharSequence rawText = result;
            Matcher matcher = GEO_URL_PATTERN.matcher(rawText);
            if (!matcher.matches()) {
              return false;
            }

            String query = matcher.group(4);

            double latitude;
            double longitude;
            double altitude;
            try {
              latitude = Double.parseDouble(matcher.group(1));
              if (latitude > 90.0 || latitude < -90.0) {
                return false;
              }
              longitude = Double.parseDouble(matcher.group(2));
              if (longitude > 180.0 || longitude < -180.0) {
                return false;
              }
              if (matcher.group(3) == null) {
                altitude = 0.0;
              } else {
                altitude = Double.parseDouble(matcher.group(3));
                if (altitude < 0.0) {
                  return false;
                }
              }
            } catch (NumberFormatException ignored) {
              return false;
            }
            return true;
          }
 
Top