Usage Signature

Developer
Aug 18, 2010 at 4:32 AM
Edited Aug 18, 2010 at 4:36 AM

I very much like this concept.  Most of the people I know don't use Regular Expressions because they think it's easier to express the validation they need in code.  But by doing that, they lose out on all the power that Regular Expression can provide.  The real trouble I think is that when you have complex expressions, eyes roll up in heads and the pursuit is dropped.  With great power comes great confusion... especially if you are the one maintaining someone else's Regular Expressions.  There's got to be a solution to this and I agree that having the "how should we do this" discussion is very relevant.

Assertions:
1.  Those who would use a RegEx wrapper are very likely the same people who may or may not know how to write complex expressions.
2.  A regular expression wrapper may also need to be a regular expression composer.  By this statement, I may be taking the project out of the original scope or insisting on a method of core construction.
3.  The use of extension methods and method chaining is the new 'norm' in code readability.  I tend to argue that lambda is in itself a bit cryptic so I suggest having two pathways of exposure so that both audiences can participate.  If you want to use lambda internally, that's fine by me, it's under the hood code.
4.  Regular Expressions become unreadable only when big fat statements are encountered, but a collection of smaller expressions grouped in composite forms might offer simplicity through segmentation and scope.

Usage Signature:
I believe the way in which the end user (developer) interacts with this sort of project will determine its success or failure.  Here's my vision on how this might look & feel:

             var regex = new Regex()
                                    .First()
                                        .Value("\d", 1, 3)
                                            .GreaterThan(1)
                                            .LessThan(255)
                                    .Next(3)
                                        .Composite()
                                            .Value(".")
                                            .Value("\d", 1, 3)
                                                .GreaterThan(0)
                                                .LessThan(255)
                                                .Last()
                                        .End()
                                    .Finalize();

The above example would show how someone could compose a Regex by chaining methods and grouping them.  The Composite() method is basically a group of values or conditions upon which act as a unit if other conditions or behaviors are applied to it.

The Last() method indicates that the value or composite it describes should be the final element in the overall expression.  Since the Last() was applied to the value within the composite, it reflects that piece, otherwise the Last() would appear after the End() method which indicates a closure of the composite and thus would be interpretted in the collective Composite being required to be the final element in the overall regular expression.  A subtle difference that may or may not affect the outcome.

or

             var regex = new Regex()
                                    .Var("Segment")
                                        .Value("\d", 1, 3)
                                            .GreaterThan(0)
                                            .LessThan(255)
                                    .First()
                                        .Variable("Segment")
                                            .Value()
                                                .Not(0)
                                    .Next(3)
                                        .Composite()
                                            .Value(".")
                                            .Variable("Segment")
                                                .Last()
                                        .End()
                                    .Finalize();
            string myExpression = regex.ToString();

The above code shows how you would store and retrieve dynamic expressions.  I was thinking that it would be nice to create an expression container app-wide for smaller common regex's for access anywhere.  For instance, you could use T4 to digest text or xml files that contain expression representations and simply add them to your project by dropping them into a folder inside the project.  This would allow people to share expressions and expression libraries by just sharing a text file.  I'm not saying that xml should ever replace Regex, but for some it might be a more understandable means of composing or organizing their thoughts.

The following code might register a variable globally.

Regex.Register("Segment")
                         .Value("\d", 1, 3)
                             .GreaterThan(0)
                             .LessThan(255)

Conclusion:
In the end, how you work with the implementation may affect it's success.  I would like the discussion to begin with a fluent UI because it might very well likely change how the wrapper is built.

Coordinator
Aug 18, 2010 at 1:38 PM

A good place to start with this concept would be to simply create a fluent syntax that maps to the existing regular expression language.  We could then create higher-order methods to wrap concepts like ranges of decimal numbers.  If we could generate expression tress from this syntax, I have another project in the works that will serialize and deserialize these expression trees to XML.  We could then publish collections of regular expression descriptors.

Coordinator
Aug 18, 2010 at 5:55 PM
Edited Aug 18, 2010 at 5:55 PM

On a somewhat related note, I figured out how to paste in code with syntax highlighting...

Copy your code out of Visual Studio, then paste using the "Paste from Word" icon on the far-right side of the toolbar when you create your post.

i.e.:

if (!target.HasValue || !arg.HasValue)
{
return Defer(target, arg);
}

var targetLimitType = (Operation == ExpressionType.Power) ? typeof(double) : target.LimitType;

var restrictions = target.Restrictions
.Merge(arg.Restrictions)
.Merge(BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType))
.Merge(BindingRestrictions.GetTypeRestriction(arg.Expression, arg.LimitType));

var targetExpr = target.Expression.ChangeType(targetLimitType).Convert(targetLimitType);
var argExpr = arg.Expression.ChangeType(targetLimitType).Convert(targetLimitType);

return new DynamicMetaObject(ExpressionEx.EnsureObjectResult(Expression.MakeBinary(Operation, targetExpr, argExpr)), restrictions);