Suppose you want to borrow regular expressions you find in javascript, perl, or other places for use with ColdFusion. Alas, not only will you need to convert them to the syntax supported by ColdFusion, but you'll need to test them to be sure they meet your needs or at least do what the author apparently thinks they'll do.
This tip builds a regular expression laboratory that makes the most common conversions for you and then lets you test the result.
<script language="javascript">
// Convert javascript regular expression to ColdFusion regex syntax
function demo(TheForm) {
Workval=TheForm.JSExpression.value;
// Overview.
// Before any other changes, add leading and trailing slashes if not present.
// For each mask type, fix leading, negated, and remaining masks.
// As the last change, remove leading and trailing slashes.
// Add leading and trailing slashes if not present.
if (Workval.search(/^\//) < 0) {
Workval='/'+Workval;
}
if (Workval.search(/\/$/) < 0) {
Workval=Workval+'/';
}
This script converts the single-letter shorthand for many character masks to a formal representation: [[:digit:]] for \d, [[:alnum:]] for \w (alphanumeric), and so forth. For each shorthand representation, it confronts two problems.
First, there may be square brackets around the shorthand, and replacing [\d] (for example) would result in [[[:digit:]]], which ColdFusion doesn't care for. So, the square brackets must be removed first.
To do this, the javascript replace method works well, but it requires a regular expression for the match and a string for the replacement. Surround the expression with forward slashes so it will have a beginning and end. Escape special characters (including backslashes) with backslashes. In this instance, almost every character gets a backslash in front of it to build the match for this replacement (because almost every character in this combination is a special character). After the trailing backslash, provide a small "g" to make this a global match, working with every instance where the match occurs. Thus, in this example, [\d] becomes \d everywhere it occurs.
Suppose the user wants to match items that were NOT digits. In this case, the user might specify [^\d]. The code needs to convert this to ^\d.
// Change /^\d and ^\d and \d digit masks Workval=Workval.replace(/\[\\d\]/g,'\\d'); Workval=Workval.replace(/\[\^\\d\]/g,'\^\\d');
Now make mask-specific changes. This isn't a simple global replacment; because, there's a second problem: the up-caret (^) has a different meaning depending on its context, and the replacement syntax varies to match that meaning. If the up-caret occurs at the beginning of the pattern, it means that the pattern must begin to match from the beginning of the input. ^\d at the beginning of the line must become ^[[:digit:]]. The up-caret anywhere else it appears negates the meaning of the match, stating that the following character or group must NOT match the input. For example, ^\d somewhere in the middle or at the end of an expression says that this portion of the pattern must NOT be a character in the 0-9 range. Oddly, the formal way to match everything that is NOT a digit is [^[:digit]].
The next three lines do the work. The first line does the conversion for a digit match at the beginning of the input. The second line does the conversion for a NON-digit match anywhere. The third line does the simple conversion for a digit match anywhere in the input.
Workval=Workval.replace(/\/\^\\d/g,'^[[:digit:]]'); Workval=Workval.replace(/\^\\d/g,'[^[:digit:]]'); Workval=Workval.replace(/\\d/g,'[[:digit:]]');
The next conversion is almost like this one, only it's backwards! \D (note the letter's case) matches NON-digits. Thus, the logic seen above has to be reversed once the brackets are stripped off. First, strip the brackets as before. Then, handle ^\D at the beginning of the expression as the desire to match something other than a digit at the beginning of the input: ^[^[:digit:]]. Handle ^\D elsewhere as the desire to match a digit (!): [[:digit:]]. Handle \D without the up-caret as the desire to match something other than a digit: [^[:digit:]].
// Change /^\D and ^\D and \D NON-digit masks // (using :digit: backwards to achieve this result) Workval=Workval.replace(/\[\\D\]/g,'\\D'); Workval=Workval.replace(/\[\^\\D\]/g,'\^\\D'); Workval=Workval.replace(/\/\^\\D/g,'^[^[:digit:]]'); Workval=Workval.replace(/\^\\D/g,'[[:digit:]]'); Workval=Workval.replace(/\\D/g,'[^[:digit:]]');
Now that we're over the hump, repeat these two sets of code (match and NON-match) for other shorthand character representations. Note that "space" includes spaces and tabs; "alnum" (alphanumeric) includes letters and digits.
// Change /^\s and ^\s and \s space masks Workval=Workval.replace(/\[\\s\]/g,'\\s'); Workval=Workval.replace(/\[\^\\s\]/g,'\^\\s'); Workval=Workval.replace(/\/\^\\s/g,'^[[:space:]]'); Workval=Workval.replace(/\^\\s/g,'[^[:space:]]'); Workval=Workval.replace(/\\s/g,'[[:space:]]'); // Change /^\S and ^\S and \S NON-space masks // (using :space: backwards to achieve this result) Workval=Workval.replace(/\[\\S\]/g,'\\S'); Workval=Workval.replace(/\[\^\\S\]/g,'\^\\S'); Workval=Workval.replace(/\/\^\\S/g,'^[^[:space:]]'); Workval=Workval.replace(/\^\\S/g,'[[:space:]]'); Workval=Workval.replace(/\\S/g,'[^[:space:]]'); // Change /^\w and ^\w and \w alphanumeric masks Workval=Workval.replace(/\[\\w\]/g,'\\w'); Workval=Workval.replace(/\[\^\\w\]/g,'\^\\w'); Workval=Workval.replace(/\/\^\\w/g,'^[[:alnum:]]'); Workval=Workval.replace(/\^\\w/g,'[^[:alnum:]]'); Workval=Workval.replace(/\\w/g,'[[:alnum:]]'); // Change /^\W and ^\W and \W NON-alphanumeric masks // (using :alnum: backwards to achieve this result) Workval=Workval.replace(/\[\\W\]/g,'\\W'); Workval=Workval.replace(/\[\^\\W\]/g,'\^\\W'); Workval=Workval.replace(/\/\^\\W/g,'^[^[:alnum:]]'); Workval=Workval.replace(/\^\\W/g,'[[:alnum:]]'); Workval=Workval.replace(/\\W/g,'[^[:alnum:]]');
Mark a place for code to perform future conversions as you come across them.
// Future Project: replace \b word-boundary/backspace mask // and its complement: \B // Make other changes here as you discover them...
Finally, ColdFusion doesn't want the leading and trailing slashes; so, remove them. Once you've done that, assign the result to a field that both you and ColdFusion can view and use. End the script.
// Last, remove leading and trailing slashes Workval=Workval.replace(/^[/]/,''); Workval=Workval.replace(/[/]$/,''); // Assign the result as the ColdFusion expression TheForm.CFExpression.value=Workval; return true; } </script>
Begin by setting defaults and opening the form. Have the form call the "demo" function (you just created) when the user submits the form. Use pre tags to simplify laying out this form.
<cfparam name="form.Data" default=""> <cfparam name="form.JSExpression" default=""> <cfparam name="form.CFExpression" default=""> <form name="Lab" method="post" onSubmit="demo(this)"> <pre> <h4>Javascript and ColdFusion Regular Expression Laboratory</h4><strong> <h5>Enter Data and a Javascript Regular Expression; Evaluate Using ColdFusion</h5>
In order to test the ability of regular expressions to detect control characters, use a textarea field instead of a text field for data input so it will accept such characters. Then provide fields to hold the javascript expression and ColdFusion expressions. For the value of each, use the appropriately named values previously defined. Define a submit button and provide instructions to the user.
Data: <cfoutput><textarea
name="Data" rows="2" cols="40">#form.Data#</textarea></cfoutput>
Javascript: <input type="text" name="JSExpression" size="70"
value=<cfoutput>"#form.JSExpression#"</cfoutput>>
ColdFusion: <input type="text" name="CFExpression" size="70"
value=<cfoutput>"#form.CFExpression#"</cfoutput>>
Pressing {Submit} converts the javascript regular expression
to a ColdFusion regular expression and uses it to evaluate the data
<input type="submit" name="Go" value="Submit">
An expression that's mis-typed or can't be parsed by the combination of this code and ColdFusion can cause a ColdFusion error. Wrap the evaluation in try-catch tags. Clear a flag beforehand, and set the flag if the evaluation fails. If the failure flag is set, complain. Otherwise, report its value. Notice that its value might not be merely 0 or 1; it could be the position of a match (which in ColdFusion starts at one, not zero as in javascript). End the form.
<cfset Oops=0> <cftry> <cfset form.Result=reFind(form.CFExpression,form.Data)> <cfcatch> <cfset Oops=1> </cfcatch> </cftry> <cfif Oops> The ColdFusion expression is not valid <cfelse> <cfoutput>The ColdFusion expression returns #form.Result#</cfoutput> </cfif> </strong> </pre> </form>
Even expressions that don't completely meet your needs or correctly survive translation can be useful. You can paste the ColdFusion version back into the javascript field, modify it there, and press submit again to use the modified result in evaluation.
More likely, you've spotted a way to handle an exceptional condition and wish to implement it. By letting you enter shorthand expressions or letting you work with formal syntax (which could be initially generated from someone else's work in shorthand), this tool lets you use whichever syntax you're more comfortable with.
Yes, some operations are better handled using syntax specific to ColdFusion, and some can't be directly translated. Some are more easily handled using multiple expressions in succession than by a master expression that handles every nuance by itself. However, this laboratory will be fine for most of the expressions you write or discover and can save your time and your wits. =Marty=