Sorcerer's IsleCode cfRegex / diff

0a116df Handle native named groups.

 src/Regex.cfc        | 26 +++++++++++++++++++-
 src/legacy/Regex.cfc | 26 +++++++++++++++++++-
 2 files changed, 50 insertions(+), 2 deletions(-)
diff --git a/src/Regex.cfc b/src/Regex.cfc
index c8aee70..d5d57dc 100644
--- a/src/Regex.cfc
+++ b/src/Regex.cfc
@@ -183,6 +183,8 @@
 
 		<cfset Variables.PatternObject = createObject("java","java.util.regex.Pattern")
 			.compile( Arguments.Pattern , Variables.ActiveModes ) />
+			
+		<cfset StructDelete(Variables,'PatternGroupNames') />
 
 	</cffunction>
 
@@ -215,6 +217,10 @@
 			</cfif>
 		</cfloop>
 
+		<cfif not StructKeyExists(Arguments,'GroupNames') and find('(?<',Variables.PatternText) >
+			<cfset Arguments.GroupNames = extractGroupNames() />
+		</cfif>
+
 		<cfif StructKeyExists(Arguments,'GroupNames')>
 			<cfif isSimpleValue(Arguments.GroupNames)>
 				<cfset Arguments.GroupNames = ListToArray(Arguments.GroupNames) />
@@ -232,6 +238,18 @@
 	</cffunction>
 
 
+	<cffunction name="extractGroupNames" returntype="Array" output="false" access="private">
+		<cfif not StructKeyExists(Variables,'PatternGroupNames') >
+			<!--- Need to extract group names from pattern, because Java doesn't provide any Matcher methods for it. --->
+			<!--- The handling of \Q..\E should be improved, but is very rarely used.  --->
+			<cfset Variables.PatternGroupNames = new Regex('(?<=\(\?<)[A-Za-z][A-Za-z0-9]*(?=>)')
+				.match( variables.PatternText.replaceAll('(?<!\\)\\Q([^\\]+|\\(?!E))*+\\E','') )
+				/>
+		</cfif>
+		<cfreturn Variables.PatternGroupNames />
+	</cffunction>
+
+
 	<!---
 		/// INTERNAL ///
 	--->
@@ -306,7 +324,7 @@
 		<cfargument name="Start"        type="Numeric"  optional  />
 		<cfargument name="Limit"        type="Numeric"  default=0 />
 		<cfargument name="ReturnType"   type="String"   default="match" hint="match|groups|namedgroups|full" />
-		<cfargument name="GroupNames"   type="any"      default="" hint="Required if returnType=NamedGroup." />
+		<cfargument name="GroupNames"   type="any"      default="" hint="Required if returnType=NamedGroup and no native named groups in pattern." />
 		<cfargument name="Callback"     type="any"      optional   hint="Function called to determine if a match is included in results." />
 		<cfargument name="CallbackData" type="Struct"   optional   hint="Extra data which is passed in to callback function." />
 
@@ -326,6 +344,12 @@
 		<cfif StructKeyExists(Arguments,'GroupNames') AND isSimpleValue(Arguments.GroupNames)>
 			<cfset Arguments.GroupNames = ListToArray(Arguments.GroupNames) />
 		</cfif>
+		<cfif isEmpty(Arguments.GroupNames) and Arguments.ReturnType eq 'namedgroups' and find('(?<',Variables.PatternText) >
+			<cfset Arguments.GroupNames = extractGroupNames() />
+		</cfif>
+		<cfif Arguments.ReturnType eq 'namedgroups' and (not StructKeyExists(Arguments,'GroupNames') or isEmpty(Arguments.GroupNames) )>
+			<cfthrow message="No named groups in pattern, and missing or empty GroupNames argument." />
+		</cfif>
 
 		<cfloop condition="Matcher.find()">
 
diff --git a/src/legacy/Regex.cfc b/src/legacy/Regex.cfc
index 193b79b..547b93b 100644
--- a/src/legacy/Regex.cfc
+++ b/src/legacy/Regex.cfc
@@ -184,6 +184,8 @@
 
 		<cfset Variables.PatternObject = createObject("java","java.util.regex.Pattern")
 			.compile( Arguments.Pattern , Variables.ActiveModes ) />
+			
+		<cfset StructDelete(Variables,'PatternGroupNames') />
 
 	</cffunction>
 
@@ -216,6 +218,10 @@
 			</cfif>
 		</cfloop>
 
+		<cfif not StructKeyExists(Arguments,'GroupNames') and find('(?<',Variables.PatternText) >
+			<cfset Arguments.GroupNames = extractGroupNames() />
+		</cfif>
+
 		<cfif StructKeyExists(Arguments,'GroupNames')>
 			<cfif isSimpleValue(Arguments.GroupNames)>
 				<cfset Arguments.GroupNames = ListToArray(Arguments.GroupNames) />
@@ -233,6 +239,18 @@
 	</cffunction>
 
 
+	<cffunction name="extractGroupNames" returntype="Array" output="false" access="private">
+		<cfif not StructKeyExists(Variables,'PatternGroupNames') >
+			<!--- Need to extract group names from pattern, because Java doesn't provide any Matcher methods for it. --->
+			<!--- The handling of \Q..\E should be improved, but is very rarely used.  --->
+			<cfset Variables.PatternGroupNames = new Regex('(?<=\(\?<)[A-Za-z][A-Za-z0-9]*(?=>)')
+				.match( variables.PatternText.replaceAll('(?<!\\)\\Q([^\\]+|\\(?!E))*+\\E','') )
+				/>
+		</cfif>
+		<cfreturn Variables.PatternGroupNames />
+	</cffunction>
+
+
 	<!---
 		/// INTERNAL ///
 	--->
@@ -307,7 +325,7 @@
 		<cfargument name="Start"        type="Numeric"  optional  />
 		<cfargument name="Limit"        type="Numeric"  default=0 />
 		<cfargument name="ReturnType"   type="String"   default="match" hint="match|groups|namedgroups|full" />
-		<cfargument name="GroupNames"   type="any"      default="" hint="Required if returnType=NamedGroup." />
+		<cfargument name="GroupNames"   type="any"      default="" hint="Required if returnType=NamedGroup and no native named groups in pattern." />
 		<cfargument name="Callback"     type="any"      optional   hint="Function called to determine if a match is included in results." />
 		<cfargument name="CallbackData" type="Struct"   optional   hint="Extra data which is passed in to callback function." />
 
@@ -327,6 +345,12 @@
 		<cfif StructKeyExists(Arguments,'GroupNames') AND isSimpleValue(Arguments.GroupNames)>
 			<cfset Arguments.GroupNames = ListToArray(Arguments.GroupNames) />
 		</cfif>
+		<cfif ArrayIsEmpty(Arguments.GroupNames) and Arguments.ReturnType eq 'namedgroups' and find('(?<',Variables.PatternText) >
+			<cfset Arguments.GroupNames = extractGroupNames() />
+		</cfif>
+		<cfif Arguments.ReturnType eq 'namedgroups' and (not StructKeyExists(Arguments,'GroupNames') or ArrayIsEmpty(Arguments.GroupNames) )>
+			<cfthrow message="No named groups in pattern, and missing or empty GroupNames argument." />
+		</cfif>
 
 		<cfloop condition="Matcher.find()">