Răsfoiți Sursa

String.substr negative length support (#12429)

* substr negative length

* update doc

* test hxcpp branch

* Update Cpp.hx

---------

Co-authored-by: Simon Krajewski <[email protected]>
RblSb 1 săptămână în urmă
părinte
comite
e4dcc00301

+ 4 - 0
src/generators/genswf9.ml

@@ -367,6 +367,10 @@ let property ctx fa t =
 		| "charCodeAt" when Gctx.defined ctx.com Define.NoFlashOverride -> ident (p ^ "HX"), None, true
 		| "charCodeAt" (* use Haxe version *) -> ident p, None, true
 		| "cca" -> as3 "charCodeAt", None, false
+
+		| "substr" when Gctx.defined ctx.com Define.NoFlashOverride -> ident (p ^ "HX"), None, true
+		| "substr" (* use Haxe version *) -> ident p, None, true
+		| "__substr__" -> as3 "substr", None, false
 		| _ -> as3 p, None, false);
 	| TInst ({ cl_path = [],"Date" },_) ->
 		(match p with

+ 19 - 2
std/String.hx

@@ -135,15 +135,32 @@ extern class String {
 
 		If `len` is omitted, all characters from position `pos` to the end of
 		`this` String are included.
+		```haxe
+		"abcde".substr(3) // de
+		```
 
 		If `pos` is negative, its value is calculated from the end of `this`
 		String by `this.length + pos`. If this yields a negative value, 0 is
 		used instead.
+		```haxe
+		"abcde".substr(-2) // de
+		```
+
+		If `len` is positive, up to `len` characters from the calculated position
+		to the end of `this` String are included.
+		```haxe
+		"abcde".substr(1, 2) // bc
+		```
+
+		If `len` is negative, all characters from the calculated position to the end
+		of `this` String, except the last `abs(len)` characters, are included.
+		```haxe
+		"abcde".substr(0, -2) // abc
+		"abcde".substr(1, -2) // bc
+		```
 
 		If the calculated position + `len` exceeds `this.length`, the characters
 		from that position to the end of `this` String are returned.
-
-		If `len` is negative, the result is unspecified.
 	**/
 	function substr(pos:Int, ?len:Int):String;
 

+ 17 - 0
std/flash/Boot.hx

@@ -386,5 +386,22 @@ class Boot extends flash.display.MovieClip {
 					return null;
 				return Std.int(x);
 			};
+			#if no_flash_override
+			String.prototype.substrHX = function(pos:Int, ?len:Int):String {
+			#else
+			String.prototype.substr = function(pos:Int, ?len:Int):String {
+			#end
+				var s:String = __this__;
+				if (len == null) len = s.length;
+				if (len < 0) {
+					if (pos < 0) {
+						pos = s.length + pos;
+						if (pos < 0)
+							pos = 0;
+					}
+					len = s.length + len - pos;
+				}
+				return s.__substr__(pos, len);
+			}
 	}
 }

+ 4 - 5
std/hl/_std/String.hx

@@ -122,16 +122,15 @@ class String {
 
 	public function substr(pos:Int, ?len:Int):String@:privateAccess {
 		var sl = length;
-		var len:Int = if (len == null) sl else len;
+		var len:Int = len ?? sl;
 		if (len == 0)
 			return "";
-		if (pos != 0 && len < 0)
-			return "";
 		if (pos < 0) {
 			pos = sl + pos;
 			if (pos < 0)
 				pos = 0;
-		} else if (len < 0) {
+		}
+		if (len < 0) {
 			len = sl + len - pos;
 			if (len < 0)
 				return "";
@@ -258,7 +257,7 @@ class String {
 		b.setUI16(2, 0);
 		return __alloc__(b, 1);
 	}
-	
+
 	@:keep static function __add__(a:String, b:String):String {
 		if (a == null)
 			a = "null";

+ 6 - 12
std/js/_std/HxOverrides.hx

@@ -67,20 +67,14 @@ class HxOverrides {
 		if (len == null) {
 			len = s.length;
 		} else if (len < 0) {
-			if (pos == 0)
-				len = s.length + len;
-			else
-				return "";
+			if (pos < 0) {
+				pos = s.length + pos;
+				if (pos < 0)
+					pos = 0;
+			}
+			len = s.length + len - pos;
 		}
 
-		#if (js_es < 5)
-		if (pos < 0) {
-			pos = s.length + pos;
-			if (pos < 0)
-				pos = 0;
-		}
-		#end
-
 		return (cast s).substr(pos, len);
 	}
 

+ 3 - 5
std/jvm/StringExt.hx

@@ -84,16 +84,14 @@ class StringExt {
 	}
 
 	public static function substr(me:String, pos:Int, ?len:Int):String {
-		var len:Int = len == null ? me.length : len;
-		if (pos != 0 && len < 0) {
-			return "";
-		}
+		var len:Int = len ?? me.length;
 		if (pos < 0) {
 			pos = me.length + pos;
 			if (pos < 0) {
 				pos = 0;
 			}
-		} else if (len < 0) {
+		}
+		if (len < 0) {
 			len = me.length + len - pos;
 		}
 		if (pos + len > me.length) {

+ 4 - 4
std/lua/_std/String.hx

@@ -159,14 +159,14 @@ class String {
 	}
 
 	public function substr(pos:Int, ?len:Int):String {
-		if (len == null || len > pos + this.length)
-			len = this.length;
-		else if (len < 0)
-			len = length + len;
+		if (len == null || pos + len > this.length)
+			len = this.length - pos;
 		if (pos < 0)
 			pos = length + pos;
 		if (pos < 0)
 			pos = 0;
+		if (len < 0)
+			len = length + len - pos;
 		return BaseString.sub(this, pos + 1, pos + len).match;
 	}
 

+ 2 - 4
std/neko/_std/String.hx

@@ -128,15 +128,13 @@
 
 		if (pos == null)
 			pos = 0;
-		if (pos != 0 && len < 0) {
-			return "";
-		}
 
 		if (pos < 0) {
 			pos = sl + pos;
 			if (pos < 0)
 				pos = 0;
-		} else if (len < 0) {
+		}
+		if (len < 0) {
 			len = sl + len - pos;
 		}
 

+ 1 - 0
std/python/internal/StringImpl.hx

@@ -153,6 +153,7 @@ class StringImpl {
 				if (startIndex < 0)
 					startIndex = 0;
 			}
+			if (len < 0) len = s.length + len - startIndex;
 			return Syntax.arrayAccess(s, startIndex, startIndex + len);
 		}
 	}

+ 15 - 2
tests/unit/src/unitstd/String.unit.hx

@@ -153,9 +153,22 @@ s.substr(0, 2) == "xf";
 s.substr(0, 100) == "xfooxfooxxbarxbarxx";
 s.substr(0, -1) == "xfooxfooxxbarxbarx";
 s.substr(0, -2) == "xfooxfooxxbarxbar";
-// s.substr(1, -2) == "fooxfooxxbarxbar";
-// s.substr(2, -2) == "ooxfooxxbarxbar";
+s.substr(1, -2) == "fooxfooxxbarxbar";
+s.substr(2, -2) == "ooxfooxxbarxbar";
 s.substr(0, -100) == "";
+s.substr(-19, -2) == "xfooxfooxxbarxbar";
+s.substr(-18, -2) == "fooxfooxxbarxbar";
+s.substr(-20, -2) == "xfooxfooxxbarxbar";
+s.substr(-100, -2) == "xfooxfooxxbarxbar";
+s.substr(-19, 2) == "xf";
+s.substr(-18, 2) == "fo";
+s.substr(-20, 2) == "xf";
+s.substr(-100, 2) == "xf";
+s.substr(-100, -100) == "";
+s.substr(17, -1) == "x";
+s.substr(17, -2) == "";
+s.substr(17, -10) == "";
+s.substr(17, -100) == "";
 // substring
 var s = "xfooxfooxxbarxbarxx";
 s.substring(0, 0) == "";