I seriously doubt it is a %Regex issue. The ? appears when some interface is converting characters to one of the many 8-bit character set codes and the source character code has a character that is not in the destination character code. This can happen to about 2**20 characters of Unicode when they are converted to any 8-bit code. It can also happen when converting 8-bit to a different 8-bit code.
Your terminal emulator and the IRIS terminal device can both do such conversions. A IRIS file device can also do such conversions. Different platforms can use different default conversions which explains why some different people cannot reproduce the results of other people.
You might be having problems with some of the unusual syntax of ObjectScript.
Like other languages created in the 1960s (E.g., FORTRAN IV and PL/I), ObjectScript does not have any reserved words. The word 'if' can be a command if it appears where a command is specified; it can be local variable if it appears where an expression value is expected; it can sometimes be a global variable or program name if it appears after '^'; it can be a function name if it appears after '$$'; it can be a macro name if it appears after '$$$'; it be a routine or procedure name if it appears after the 'do' command; if can sometimes be a method or a property name if it appears after '.'; etc.
Your macros
#define TestIf(%arr) if %arr>0 QUIT 5 ;; legacy IF command
#define TestIf(%arr) if (%arr>0) {QUIT 5} ;; more modern IF command
looks as if TestIf should be expanded where a command is expected so that it conditionally executes the command 'QUIT 5' which would exit the current function with a return value of 5.
However, your macro placement
set a = $$$TestIf(3)
looks like $$$TestIf is going to be an expression containing a value for the right side of an assignment (a SET command). It expands as
set a = if 3 < 0 QUIT 5
which is a syntactically correct assignment of 'a' assigned the value of the variable 'if' and that 'set' command is followed by a command named '3' which is bad syntax.
Your macro
#define logDebug(%arr) $SELECT(^GlFSL("Debug")>0:Entry^HS.Local.VA.Util.Log(%arr,,"D"),:QUIT)
looks like a macro containing the built-in '$select' function and the macro should expand into conditional expression (as opposed to a macro containing the command 'if' which should expand in to a conditional statement.) The first $select argument ^GlFSL("Debug")>0:Entry^HS.Local.VA.Util.Log(%arr,,"D") evaluates ^GlFSL("Debug")>0 and it that comparison is true, the $select evaluates Entry^HS.Local.VA.Util.Log(%arr,,"D") as the final value of the $select expression. If the selector of the first argument is false then $select goes on the second argument ,:QUIT. This has the syntax for the default value of a argument of the built-in $case function rather than be correct syntax for a $select argument. For a $select you would write 1:QUIT which would return the value of the QUIT variable. However, I suspect you might have wanted a QUIT command which would terminated the current routine/procedure. In that case you should write the conditional commands
if ^GlFSL("Debug")>0 then { set temp=Entry^HS.Local.VA.Util.Log(%arr,,"D")} else {QUIT}
if you do not execute the QUIT command then you can continue executing the next command line using the conditionally set 'temp' variable.
I am going to assume that local variable 'identifiers' contains an oref referencing either the %DynamicArray or the %DynamicObject class. If the 'identifiers' value is an oref that references some other class then ignore everything else in this reply.
Let us assume 'identifiers' refers to a %DynamicArray object (although a reference to a %DynamicObject would involve a similar discussion.) Each entry in the %DynamicArray is a JSON value. Those entries have one the following types: "null", "boolean", "number", "oref", "object", "array" or "string". One these type strings will be returned in variable 'type' specifying which JSON value was converted to an ObjectScript value that was returned in argument variable 'value'. The 'type' "array" means the returned 'value' is a nested %DynamicArray reference; the 'type' 'object' means the returned 'value' is a nested %DynamicObject reference; and the 'type' "oref" means the returned 'value' is some other ObjectScript class object reference. All other 'type' string values will mean that 'value' does not contain an oref.
The statement 'set type = value.%Get("type") is only legal in ObjectScript when 'type' contains the "array", "object" or "oref" type strings. All other type strings will cause 'value.%Get("type") to signal an <INVALID OREF> error. Most likely you want 'value' to be a reference to a nested %DynamicObject containing a JSON entry using the key name "type".
[[ If 'value' contains the "array" type reference then 'value.%Get(arg)' would expect 'arg' to be a number rather than a string. If 'value' contains an "oref" type reference then 'value' would be a different ObjectScript oref which must reference a class object containing a method named '%Get'. And other types for the 'value' argument would signal <INVALID OREF> since the 'value.%Get("type")' syntax requires 'value' to an oref and the other 'type' possibilities are not oref values. ]]
The other statement 'set text = type.%Get("text")' will always signal <INVALID OREF> since %GetNext always returns a string value in the 'type' variable passed as the third argument.
So, let's assume 'identifiers' contains a JSON array where every entry in the array is a JSON object containing information about an identifier. In this case you would know the type of each array element so you could iterate calling %GetNext(.key,.value), although if you did call %GetNext(.key,.value,.type) then immediately after the %GetNext call you could test for a data error with:
if type'="object" { do $$$ERROR($$$GeneralError,"Invalid identifier object") }
You could then look at 'value."type"' and 'value."text"' to get the 'type' and textual name from the JSON object describing an identifier. [[ You do not need the %Get method when you are using a string literal as the key name of a %DynamicObject entry. Using 'value.%Get(key)' is only needed when 'key' is a run-time key name expression. ]]