Jelajahi Sumber

[jvm][java] fix Std.parseInt() for haxedecimal with leading whitespaces

Aleksandr Kuzmenko 5 tahun lalu
induk
melakukan
3513b54515
4 mengubah file dengan 51 tambahan dan 69 penghapusan
  1. 0 1
      std/cs/_std/Std.hx
  2. 43 66
      std/java/_std/Std.hx
  3. 6 2
      std/jvm/_std/Std.hx
  4. 2 0
      tests/unit/src/unitstd/Std.unit.hx

+ 0 - 1
std/cs/_std/Std.hx

@@ -81,7 +81,6 @@ import cs.internal.Exceptions;
 
 		var ret = 0;
 		var base = 10;
-		var i = -1;
 		var len = x.length;
 		var foundCount = 0;
 		var sign = 0;

+ 43 - 66
std/java/_std/Std.hx

@@ -59,77 +59,54 @@ import java.internal.Exceptions;
 		return cast x;
 	}
 
-	@:functionCode('
-		if (x == null) return null;
-
-		int ret = 0;
-		int base = 10;
-		int i = 0;
-		int len = x.length();
-
-		if (x.startsWith("0") && len > 2)
-		{
-			char c = x.charAt(1);
-			if (c == \'x\' || c == \'X\')
-			{
-				i = 2;
-				base = 16;
-			}
-		}
-
-		boolean foundAny = i != 0;
-		boolean isNeg = false;
-		for (; i < len; i++)
-		{
-			char c = x.charAt(i);
-			if (!foundAny)
-			{
-				switch(c)
-				{
-					case \'-\':
-						isNeg = true;
-						continue;
-					case \'+\':
-					case \'\\n\':
-					case \'\\t\':
-					case \'\\r\':
-					case \' \':
-						if (isNeg) return null;
-						continue;
-				}
-			}
+	public static function parseInt(x:String):Null<Int> {
+		if (x == null)
+			return null;
 
-			if (c >= \'0\' && c <= \'9\')
-			{
-				if (!foundAny && c == \'0\')
-				{
-					foundAny = true;
+		var ret = 0;
+		var base = 10;
+		var len = x.length;
+		var foundCount = 0;
+		var sign = 0;
+		var firstDigitIndex = 0;
+		var lastDigitIndex = -1;
+		var previous = 0;
+
+		for(i in 0...len) {
+			var c = StringTools.fastCodeAt(x, i);
+			switch c {
+				case _ if((c > 8 && c < 14) || c == 32):
+					if(foundCount > 0) {
+						return null;
+					}
 					continue;
-				}
-				ret *= base; foundAny = true;
-
-				ret += ((int) (c - \'0\'));
-			} else if (base == 16) {
-				if (c >= \'a\' && c <= \'f\') {
-					ret *= base; foundAny = true;
-					ret += ((int) (c - \'a\')) + 10;
-				} else if (c >= \'A\' && c <= \'F\') {
-					ret *= base; foundAny = true;
-					ret += ((int) (c - \'A\')) + 10;
-				} else {
+				case '-'.code if(foundCount == 0):
+					sign = -1;
+				case '+'.code if(foundCount == 0):
+					sign = 1;
+				case '0'.code if(foundCount == 0 || (foundCount == 1 && sign != 0)):
+				case 'x'.code | 'X'.code if(previous == '0'.code && ((foundCount == 1 && sign == 0) || (foundCount == 2 && sign != 0))):
+					base = 16;
+				case _ if('0'.code <= c && c <= '9'.code):
+				case _ if(base == 16 && (('a'.code <= c && c <= 'z'.code) || ('A'.code <= c && c <= 'Z'.code))):
+				case _:
 					break;
-				}
-			} else {
-				break;
+			}
+			if((foundCount == 0 && sign == 0) || (foundCount == 1 && sign != 0)) {
+				firstDigitIndex = i;
+			}
+			foundCount++;
+			lastDigitIndex = i;
+			previous = c;
+		}
+		if(firstDigitIndex <= lastDigitIndex) {
+			var digits = x.substring(firstDigitIndex + (base == 16 ? 2 : 0), lastDigitIndex + 1);
+			return try {
+				(sign == -1 ? -1 : 1) * java.lang.Integer.parseInt(digits, base);
+			} catch(e:java.lang.NumberFormatException) {
+				null;
 			}
 		}
-
-		if (foundAny)
-			return isNeg ? -ret : ret;
-		else
-			return null;
-	')
-	public static function parseInt(x:String):Null<Int> {
 		return null;
 	}
 

+ 6 - 2
std/jvm/_std/Std.hx

@@ -69,10 +69,14 @@ class Std {
 	public static function parseInt(x:String):Null<Int> {
 		try {
 			x = StringTools.trim(x);
-			if (x.length < 2) {
+			var signChars = switch (cast x : java.NativeString).codePointAt(0) {
+				case '-'.code | '+'.code: 1;
+				case _: 0;
+			}
+			if (x.length < 2 + signChars) {
 				return integerFormatter.parse(x).intValue();
 			}
-			switch ((cast x : java.NativeString).codePointAt(1)) {
+			switch ((cast x : java.NativeString).codePointAt(1 + signChars)) {
 				case 'x'.code | 'X'.code:
 					return java.lang.Integer.decode(x).intValue();
 				case _:

+ 2 - 0
tests/unit/src/unitstd/Std.unit.hx

@@ -55,6 +55,7 @@ Std.int(0.2) == 0;
 
 // parseInt
 Std.parseInt("0") == 0;
+Std.parseInt("-1") == -1;
 Std.parseInt("   5") == 5;
 Std.parseInt("0001") == 1;
 Std.parseInt("0010") == 10;
@@ -78,6 +79,7 @@ Std.parseInt("0x01") == 1;
 Std.parseInt('  	-0x10') == -16;
 #end
 #end
+#end
 
 // parseFloat
 Std.parseFloat("0") == 0.;