<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://weblogs.asp.net/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Justin Rogers : Regular Expressions</title><link>http://weblogs.asp.net/justin_rogers/archive/tags/Regular+Expressions/default.aspx</link><description>Tags: Regular Expressions</description><dc:language>en</dc:language><generator>CommunityServer 2007 SP1 (Build: 20510.895)</generator><item><title>Testing: GC Sanity Checks in Whidbey</title><link>http://weblogs.asp.net/justin_rogers/archive/2004/10/02/237003.aspx</link><pubDate>Sat, 02 Oct 2004 16:42:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:237003</guid><dc:creator>Justin Rogers</dc:creator><author>Justin Rogers</author><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/justin_rogers/rsscomments.aspx?PostID=237003</wfw:commentRss><comments>http://weblogs.asp.net/justin_rogers/archive/2004/10/02/237003.aspx#comments</comments><description>&lt;p&gt;I have a feeling this method will only be useful when you can run a series of tests without any collections taking place during your tests. Whenever a collection occurs you can never be sure of the amount of time spent in collection (anyone on the CLR want to surface that number without going to performance counters?) so you can't really get an understanding of how badly your test was affected. I've managed to run some rather long tests without any collections by pre-allocating everything to be used by the testing structure and avoiding additional allocations during the test process. Here is how I check for collections:&lt;/p&gt; &lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt; &lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt; &lt;p&gt;// Before my test&lt;br /&gt;int[] collections = new int[3];&lt;br /&gt;collections[0] = GC.CollectionCount( 0 );&lt;br /&gt;collections[1] = GC.CollectionCount( 1 );&lt;br /&gt;collections[2] = GC.CollectionCount( 2 );&lt;/p&gt; &lt;p&gt;// After my test&lt;br /&gt;Console.WriteLine( "Collections: {0}, {1}, {2}",&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GC.CollectionCount( 0 ) - collections[0],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GC.CollectionCount( 1 ) - collections[1],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GC.CollectionCount( 2 ) - collections[2] );&lt;/p&gt;&lt;/blockquote&gt;&lt;/blockquote&gt; &lt;p dir="ltr"&gt;What I've realized from this little method is that pre-allocating the testing structure really does make a huge difference. I can see 5 or 6 collections if my objects are allocated on the fly during the test and 0 collections if the are pre-allocated into an array or similar structure. Now, in many tests you aren't going to avoid allocating new objects during the test. In many cases the sole purpose of the test is to allocate new objects, such as return strings, or other data. If that is the case, you might want to look for a balance in the collection count between both of your testing methods, test multiple times, test for short periods and average over a large number of separate test loops, or use high performance counters to avoid the DateTime round-off issues.&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=237003" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Regular+Expressions/default.aspx">Regular Expressions</category><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Testing/default.aspx">Testing</category><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Whidbey/default.aspx">Whidbey</category></item><item><title>Regex: MatchCollection uses delay matching for performance</title><link>http://weblogs.asp.net/justin_rogers/archive/2004/09/07/226273.aspx</link><pubDate>Tue, 07 Sep 2004 09:27:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:226273</guid><dc:creator>Justin Rogers</dc:creator><author>Justin Rogers</author><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/justin_rogers/rsscomments.aspx?PostID=226273</wfw:commentRss><comments>http://weblogs.asp.net/justin_rogers/archive/2004/09/07/226273.aspx#comments</comments><description>&lt;p&gt;There are several ways to get all of the matches of an expression over the source input, but the most popular probably has to be the &lt;u&gt;Matches&lt;/u&gt; method which returns a &lt;u&gt;MatchCollection&lt;/u&gt;. What most people don't know, and I didn't until recently, is that the actual call to &lt;u&gt;Matches&lt;/u&gt; doesn't do any work. It returns a shell that only does work when you actually request the results.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Count&lt;br /&gt;&lt;/strong&gt;This property is responsible for why most people probably can't tell the difference. Once you get a &lt;u&gt;MatchCollection&lt;/u&gt; the first thing you do is check the &lt;u&gt;Count&lt;/u&gt; property. All this does is force the &lt;u&gt;MatchCollection&lt;/u&gt; to run the expression and fill the internal structures. When you do this, all of the delay loading potential is removed so the underlying collection knows how many matches are present.&lt;/p&gt; &lt;p&gt;This definitely posed some problems for the &lt;a id="CategoryEntryList" href="/justin_rogers/archive/2004/05/22/139337.aspx"&gt;Asynchronous Regular Expressions using the ThreadPool and a cancellation model.&lt;/a&gt;&amp;nbsp;We rewrote the code there to just return a &lt;u&gt;MatchCollection&lt;/u&gt; but for some reason it was completing extremely fast all the time and we couldn't figure out why in the hell that was happening. Well, we went ahead and made a call to &lt;u&gt;Count&lt;/u&gt; within the runner thread and now everything works as it should.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;this[int i]&lt;br /&gt;&lt;/strong&gt;The default indexed property for getting access to &lt;u&gt;Match&lt;/u&gt; classes is delay loaded, assuming you don't call &lt;u&gt;Count&lt;/u&gt; first. You can pass any index you want to this bad boy, and it'll load all of the matches in between (if they aren't already loaded), and then service the match index you just passed in. Here is where I consider the bad code to start in. If the match doesn't exist, they internally return a null, so if you ask for match 20 and there are only 8, null will get returned &lt;strong&gt;internally&lt;/strong&gt; but they'll throw a &lt;u&gt;ArgumentOutOfRangeException&lt;/u&gt; &lt;strong&gt;externally&lt;/strong&gt;.&lt;/p&gt; &lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt; &lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt; &lt;p&gt;// Normally this would be possible&lt;br /&gt;Match m = null;&lt;br /&gt;for(int&amp;nbsp;i = 0; (m = matches[i]) != null; i++) {&lt;br /&gt;}&lt;/p&gt; &lt;p&gt;// You could optimize for a specific count&lt;br /&gt;Match m = null;&lt;br /&gt;for(int&amp;nbsp;i = 0; i &amp;lt; 5 &amp;amp;&amp;amp; (m = matches[i]) != null; i++) {&lt;br /&gt;}&lt;/p&gt;&lt;/blockquote&gt;&lt;/blockquote&gt; &lt;p dir="ltr"&gt;Unfortunately, the above two constructs aren't possible because of the exception, however, they would be the ideal way to process matches without loading all of the work into a single call.&lt;/p&gt; &lt;p dir="ltr"&gt;&lt;strong&gt;Enumerator&lt;br /&gt;&lt;/strong&gt;They do have an enumerator that I guess you really have to use if you want true delay loading syntax without that lame exception. This works out well because it balances the matching work between working with the match and we are no longer front-loaded. This allows us to make a number of syntaxes available, including processing pattern matches for a specific match, or processing only a specific number of matches.&lt;/p&gt; &lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt; &lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt; &lt;p dir="ltr"&gt;// Process until we find the match we want&lt;br /&gt;foreach(Match m in matches) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( m.Groups[4].Value == "choice X" ) { /* Do Work */ break; }&lt;br /&gt;}&lt;/p&gt; &lt;p dir="ltr"&gt;// Process the first n matches&lt;br /&gt;int count = 0;&lt;br /&gt;foreach(Match m in matches) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Do work&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( ++count == 5 ) { return; }&lt;br /&gt;}&lt;/p&gt;&lt;/blockquote&gt;&lt;/blockquote&gt; &lt;p dir="ltr"&gt;We don't stop there. You can also enable RightToLeft matching in an attempt to get the last n matches instead of the first n. You start to see where you get some interesting options for processing a string for multiple matches while still have great control over your performance. Considering various patterns can hang the regular expression engine knowing how and where to use multi-threaded abortable operations can really save you from hanging your application.&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=226273" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/CLR+Internals/default.aspx">CLR Internals</category><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Regular+Expressions/default.aspx">Regular Expressions</category></item><item><title>Regex: Functionality about named/numbered groups everyone should know.</title><link>http://weblogs.asp.net/justin_rogers/archive/2004/09/06/226183.aspx</link><pubDate>Mon, 06 Sep 2004 23:31:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:226183</guid><dc:creator>Justin Rogers</dc:creator><author>Justin Rogers</author><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/justin_rogers/rsscomments.aspx?PostID=226183</wfw:commentRss><comments>http://weblogs.asp.net/justin_rogers/archive/2004/09/06/226183.aspx#comments</comments><description>&lt;p&gt;We have a cool new tool amongst us over on &lt;a href="http://www.regexlib.com/RETester.aspx"&gt;http://www.regexlib.com/RETester.aspx&lt;/a&gt;. It is already more functional than the previous tool there that was receiving quite a bit of traffic and attention for quickly testing expressions. The new tool really focuses on debug and diagnostic information that can be used to help tune an expression. More will be added for certain, but just the past day a more detailed group capture view was added that presented a few problems.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Explicitly Numbered Groups&lt;br /&gt;&lt;/strong&gt;This one isn't strange at all, in fact it is only because of extensions by the .NET expression engine that they might be confusing. Numbered groups allow you to change the index of a given capture. If you are working with the GroupCollection you might write the following code in order to enumerate all of the groups. This will print out Group[0] which is always present, but then it will try to point out Group[1]. This will succeed, but not print anything if the expression looks like, "(?&amp;lt;10&amp;gt;111)" and given the input "111";&lt;/p&gt; &lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt; &lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt; &lt;p&gt;for(int i&amp;nbsp;= 0; i &amp;lt; m.Groups.Count; i++) { Console.WriteLine(m.Groups[i]); }&lt;/p&gt;&lt;/blockquote&gt;&lt;/blockquote&gt; &lt;p&gt;What you need to do is get a list of group numbers using the &lt;u&gt;Regex.GetGroupNumbers&lt;/u&gt; method. This returns&amp;nbsp;an array of indexes you can use instead of simply dropping blind into the group collection. Another common mistake may also be a &lt;u&gt;foreach&lt;/u&gt; or enumeration of the group collection. If you do this, you will get all captures, but you won't be able to retrieve their name or number.&lt;/p&gt; &lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt; &lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt; &lt;p&gt;// BAD&lt;br /&gt;foreach(Group g in m.Groups) { }&lt;br /&gt;// GOOD&lt;br /&gt;int[] groups = regex.GetGroupNumbers();&lt;br /&gt;for(int i = 0; i &amp;lt; groups.Length; i++) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Group g = m.Groups[groups[i]];&lt;br /&gt;}&lt;/p&gt;&lt;/blockquote&gt;&lt;/blockquote&gt; &lt;p dir="ltr"&gt;&lt;strong&gt;Named and Numbered Reordering&lt;br /&gt;&lt;/strong&gt;All named captures are also given a number, but they aren't given a number in-line with their ordering within the expression. They are actually assigned numbers after all of the numbered groups have been allocated. That means the expression "(?&amp;lt;name&amp;gt;99)(9)" would return the 9 as the 1st ordered group and 99 as the second ordered group. If you name a group, be careful when you mix and match with unnamed groups because the indexes are not going to be what you might initially think.&lt;/p&gt; &lt;p dir="ltr"&gt;&lt;strong&gt;Numbering Bug&lt;br /&gt;&lt;/strong&gt;Explicitly numbered groups may get overwritten by groups whose indexes are automatically assigned. For instance, if you start an expression by numbering a group, say "(?&amp;lt;10&amp;gt;99)", then go on to create an expression with more than 9 anonymous groups, you'll find that the 10th group gets overwritten or shared. The resulting Value of group 0 is the full capture, but the value present in group 10 will be the value of whatever group is processed last. This is best examined than talked about.&lt;/p&gt; &lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt; &lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt; &lt;p dir="ltr"&gt;private static Regex regex2 = new Regex("(?&amp;lt;10&amp;gt;99)(9)(9)(9)(9)(9)(9)(9)(9)(9)(9a)(9)(9)(9)(9)(9)(9)(?&amp;lt;20&amp;gt;99)");&lt;br /&gt;private static string data1 = "999999999999a9999999999999999";&lt;/p&gt;&lt;/blockquote&gt;&lt;/blockquote&gt; &lt;p dir="ltr"&gt;For the results, how many groups print the value "99", how many groups print the value "9a". Further, count the number of 9's in the group 0, and the number of 9's in the rest of the groups. Do they even match? Have fun with this and be careful. Regular expressions are supposed to make your life easier, but there are some gotchas.&lt;/p&gt; &lt;p dir="ltr"&gt;&lt;strong&gt;References:&lt;br /&gt;&lt;/strong&gt;[1] &lt;a id="CategoryEntryList" href="/justin_rogers/archive/2004/02/13/72800.aspx"&gt;&lt;font color="#0000ff"&gt;Match vs MatchSparse, a regular expression implementation detail that may surprise you.&lt;/font&gt;&lt;/a&gt;&lt;br /&gt;[2] &lt;a id="CategoryEntryList" href="/justin_rogers/archive/2004/09/04/225692.aspx"&gt;The extended .NET Regular Expression tester is up on www.RegexLib.com&lt;/a&gt;&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=226183" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/CLR+Internals/default.aspx">CLR Internals</category><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Quick+Tips/default.aspx">Quick Tips</category><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Regular+Expressions/default.aspx">Regular Expressions</category></item><item><title>The extended .NET Regular Expression tester is up on www.RegexLib.com</title><link>http://weblogs.asp.net/justin_rogers/archive/2004/09/04/225692.aspx</link><pubDate>Sat, 04 Sep 2004 20:13:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:225692</guid><dc:creator>Justin Rogers</dc:creator><author>Justin Rogers</author><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/justin_rogers/rsscomments.aspx?PostID=225692</wfw:commentRss><comments>http://weblogs.asp.net/justin_rogers/archive/2004/09/04/225692.aspx#comments</comments><description>&lt;p&gt;Hey guys, figured I'd ping everyone and tell them this little jewel was out and ready to go. You can test your expressions any time you have an internet connection and use some extended features like source from file/web. I have to say the tool is more and more functional every day as new options are being added. Here is a quick overview of the current options:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Client or Server Side Testing - Test against the .NET engine or the browser vb/jscript implementations.&lt;/li&gt; &lt;li&gt;Some new buttons allow you to quickly add your current pattern to the repository on RegexLib or go grab some existing expressions.&lt;/li&gt; &lt;li&gt;You can now specify all of the capturing options for the expression right up front.&lt;/li&gt; &lt;li&gt;The source for an expression can be retrieved for you by an external data source.&lt;/li&gt; &lt;li&gt;Selecting groups and captures in the results window will result in the item captured in the source being highlighted.&lt;/li&gt; &lt;li&gt;And the same asynchronous runner is being used so those runaway expressions won't have you waiting hours for a return, instead they'll conk out after only a few prolonged seconds.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Some of the options that have been tossed back and forth include:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Formalize the tab structure to include documentation, display options, and more. That middle documentation panel is like a window into another universe and we want to make sure the other universe is full of great information.&lt;/li&gt; &lt;li&gt;I've tossed my hand in to include nested groups as nested items in the tree structure... The flat layout of group numbers doesn't portray this, but the offset+length values do give you an idea of where groups are in&amp;nbsp;the hierarchy.&lt;/li&gt; &lt;li&gt;I'm hoping to translate some C# code to aid with screen scraping into JScript so the functions can generate expressions on the client-side. The basic premise is that by feeding some source value, and then tagging all of the ranges you can more easily design a range by telling the code what type of data will be present so it can create an appropriate pattern for that portion. This doesn't work on extremely dynamic patterns, such as date-times, etc... But it would allow you to work on something simpler, especially the not-so-complex layout of a table row within an HTML page.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Go check it out: &lt;a href="http://www.regexlib.com/RETester.aspx"&gt;http://www.regexlib.com/RETester.aspx&lt;/a&gt;, and make sure to give plenty of feedback on issues. I guess there were a ton last night, but I'm seeing that everything I've tested today works well.&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=225692" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Regular+Expressions/default.aspx">Regular Expressions</category></item><item><title>Regular Expression posts of recent note on blogs.RegexAdvice.com</title><link>http://weblogs.asp.net/justin_rogers/archive/2004/08/10/211773.aspx</link><pubDate>Tue, 10 Aug 2004 10:06:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:211773</guid><dc:creator>Justin Rogers</dc:creator><author>Justin Rogers</author><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/justin_rogers/rsscomments.aspx?PostID=211773</wfw:commentRss><comments>http://weblogs.asp.net/justin_rogers/archive/2004/08/10/211773.aspx#comments</comments><description>&lt;P&gt;Justin Rogers: &lt;A id=_74af7b23657_HomePageDays_DaysList__ctl0_DayItem_DayList__ctl0_TitleUrl href="http://blogs.regexadvice.com/justin_rogers/archive/2004/08/10/1477.aspx"&gt;What does conditional matching really mean in a regular expression?&lt;/A&gt;&lt;BR&gt;Justin Rogers: &lt;A id=_74af7b23657_HomePageDays_DaysList__ctl1_DayItem_DayList__ctl0_TitleUrl href="http://blogs.regexadvice.com/justin_rogers/archive/2004/08/06/1460.aspx"&gt;The not so basics of NOT!&lt;/A&gt;&lt;BR&gt;Darren Neimke: &lt;A id=viewpost.ascx_TitleUrl href="http://blogs.regexadvice.com/dneimke/archive/2004/08/10/1473.aspx"&gt;Cleaning a list perf. test&lt;/A&gt; &lt;BR&gt;Darren Neimke: &lt;A id=viewpost.ascx_TitleUrl href="http://blogs.regexadvice.com/dneimke/archive/2004/08/03/1432.aspx"&gt;The sugary synax we love... Lookaround &lt;/A&gt;&lt;/P&gt;
&lt;P&gt;To note both of my posts are on reduction. Taking advanced syntax features and turning them into more basic syntax that may be more verbose but requires a lighter support of the regular expressions standard. Darren's post start with a killer reason for using look-around assertions. I assert that any expression can be rewritten without a look-around assertion and I've been on a rampage trying to rewrite all of Darren's and Michael's expressions and removing any assertions in the process.&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=211773" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Regular+Expressions/default.aspx">Regular Expressions</category></item><item><title>Darren's "Killer Reason for LookAround" posting has been haunting me</title><link>http://weblogs.asp.net/justin_rogers/archive/2004/08/04/208473.aspx</link><pubDate>Thu, 05 Aug 2004 02:32:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:208473</guid><dc:creator>Justin Rogers</dc:creator><author>Justin Rogers</author><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/justin_rogers/rsscomments.aspx?PostID=208473</wfw:commentRss><comments>http://weblogs.asp.net/justin_rogers/archive/2004/08/04/208473.aspx#comments</comments><description>&lt;P&gt;Darren's Post: &lt;A href="http://blogs.regexadvice.com/dneimke/archive/2004/08/03/1432.aspx"&gt;http://blogs.regexadvice.com/dneimke/archive/2004/08/03/1432.aspx&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Every time he comes up with a posting like the above I get an instant message of some sort or another with a quizzical question, &amp;#8220;Hehe, you want to be unproductive today!&amp;#8221; or something similarly intriguing. That is how I was introduced to the killer reason for a lookaround challenge. I have to say, I can't find one. At this point it is apparent that look-around expressions might just be a shortcut for a more verbose expression. I've managed to convert nearly all of my library and many other's libraries of look-around expressions to something either simpler/more complex that was not a look-around expression, but instead&amp;nbsp;a normal expression not containing assertions.&lt;/P&gt;
&lt;P&gt;Based on these concepts we kind of changed the rules a bit. The new rules stated that we needed to find a place where assertions would provide better performance. And so I started to extrapolate some conditions that would help increase our chances of finding a great case for assertions.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Create a simple bounding match with a start marker and an end marker where marker stands for some pattern or literal.&lt;/LI&gt;
&lt;LI&gt;Between the start and end markers create a relatively complex matching pattern that in many cases would take a long time to execute.&lt;/LI&gt;
&lt;LI&gt;Now assure that the most probably input scenario will match the start marker, and most or all of the complex expression, but not the end marker.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Hopefully you see where I'm going here. Rather than having a huge inline expression to match the conditional rules in the middle in a scenario where the end tag is more likely to cause the pattern to fail, instead apply the complex conditional rules only after matching the start and end tags. We still can't think of anything really stellar, but at least now we have some patterns that do provide better performance using assertions over a normal expression.&lt;/P&gt;
&lt;P&gt;I also have another pattern that I don't think can really be done without assertions. However, they can't be done because an assertion is the only way to introduce the (NOT) operator in regular expressions. Well, not the only way, because you can have negative character classes that have a kind of (NOT) operator but they don't work at the same level. They work on characters and can't work on patterns of characters.&amp;nbsp; Here are the two input strings the embody my pattern:&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;[foo][bar][/bar][/foo]&lt;BR&gt;[foo][bar][/foo][/bar]&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P dir=ltr&gt;Basically, I want to look for start and end groups that cross one another. This pattern could be used to find errors in some proprietary sound mixing format where each sound sample should start and end, but never overlap in time sequence with another. Maybe this is a valdiator tool that gets run at the end of the entire process but allowing the mixing of sounds early on is something that has to be accounted for. Anyway, I want to be able to match one of the patterns, the second one, and ensure that I'm not matching an extended case of the first.&lt;/P&gt;
&lt;P dir=ltr&gt;How can I say match [foo][bar][/foo], but ensure that [/bar] doesn't occur preceeding [/foo]? Well that is an assertion. A look-behind assertion to be precise. Then how do I say match [/bar] following [/foo]. Well that is easy, no assertions are needed there, just a normal match literal.&amp;nbsp; &lt;STRONG&gt;Note: This is a simplification of the pattern. There may be any number of whitespace or other characters between some of the tags which is why the look-behinds are necessary.&lt;/STRONG&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P dir=ltr&gt;"&lt;A href="file://\\[(\\w+?)\\]\\[(\\w+?)\\](?&lt;!\\[/\\2\\])\\[/\\1\\]\\[/\\2\\"&gt;\\[(\\w+?)\\]\\[(\\w+?)\\](?&amp;lt;!\\[/\\2\\])\\[/\\1\\]\\[/\\2\\&lt;/A&gt;]"&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P dir=ltr&gt;Now, the astute user might point out with the two input strings, becuase we have the following [/\2] pattern the first string won't match. Remember we might be running this over a string of the form [foo][bar][/bar][/foo][/bar] for all we know. In other words we want the pattern to be more resilient to failure. Even with this type of pattern, there is always something else you can use in place of the assertions. Conditional matches for instance could be used. If I match the second end tag before the first end tag then I could conditionally choose to search for the beginning of the string as the next character versus the second end tag. This basically forces a failure.&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P dir=ltr&gt;"&lt;A href="file://\\[(\\w+?)\\]\\[(\\w+?)\\](\\[/\\2\\])?\\[/\\1\\](?(3)^|\\[/\\2\\"&gt;\\[(\\w+?)\\]\\[(\\w+?)\\](\\[/\\2\\])?\\[/\\1\\](?(3)^|\\[/\\2\\&lt;/A&gt;])"&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P dir=ltr&gt;If you think you might have some patterns that are impossible without assertions then toss them into my comments. I'd be glad to play around and see about converting them to not use assertions. So far everything I've come up with is bust. Some other popular regex bloggers are coming to the same conclusions as well. Wayne King had an &amp;lt;img&amp;gt; matcher that relied on look-behind but then realized a simple expression would do. Darren has been wracking his brains for days as have I. &lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=208473" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Algorithms/default.aspx">Algorithms</category><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Regular+Expressions/default.aspx">Regular Expressions</category></item><item><title>Bringing an end to the posts on decompositions of numeric ranges into validating regular expressions.</title><link>http://weblogs.asp.net/justin_rogers/archive/2004/05/25/140982.aspx</link><pubDate>Tue, 25 May 2004 07:50:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:140982</guid><dc:creator>Justin Rogers</dc:creator><author>Justin Rogers</author><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/justin_rogers/rsscomments.aspx?PostID=140982</wfw:commentRss><comments>http://weblogs.asp.net/justin_rogers/archive/2004/05/25/140982.aspx#comments</comments><description>&lt;P&gt;I've posted quite a few items covering the process of decomposition.&amp;nbsp; Most of the examinations are textual only and cover the process of generating decompositions by hand.&amp;nbsp; I've since issued a challenge for the creation of an algorithm that would automatically handle a given range and return the decomposition in regular expression format that could be used to validate input in the range.&amp;nbsp; I talked through a sample algorithm that had some issued, then covered&amp;nbsp;these issues, and finally posted my own algorithm in C# that creates a matching alternation group that isn't minimally sized, but works for the give range.&amp;nbsp; Have a look.&lt;/P&gt;
&lt;P&gt;The Beginning: &lt;A id=_75deabd9a8f_HomePageDays_DaysList__ctl2_DayItem_DayList__ctl1_TitleUrl href="http://blogs.regexadvice.com/justin_rogers/archive/2004/05/21/1139.aspx"&gt;Value range parsing using Regular Expressions. Breaking down the dotted decimal IP byte processing.&lt;/A&gt;&lt;BR&gt;Follow-up on ranges: &lt;A id=_75deabd9a8f_HomePageDays_DaysList__ctl1_DayItem_DayList__ctl1_TitleUrl href="http://blogs.regexadvice.com/justin_rogers/archive/2004/05/22/1147.aspx"&gt;&lt;FONT color=#0000ff&gt;0 through N ranges are interesting, but what about M through N ranges.&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;Some Oddities that are hard to handle: &lt;A id=_75deabd9a8f_HomePageDays_DaysList__ctl0_DayItem_DayList__ctl1_TitleUrl href="http://blogs.regexadvice.com/justin_rogers/archive/2004/05/24/1160.aspx"&gt;That range algorithm was more difficult than I originally pointed out due to some strange oddities.&lt;/A&gt;&lt;BR&gt;The post reference the article and algorithm: &lt;A id=_75deabd9a8f_HomePageDays_DaysList__ctl0_DayItem_DayList__ctl0_TitleUrl href="http://blogs.regexadvice.com/justin_rogers/archive/2004/05/24/1162.aspx"&gt;An Algorithm has been prepared, I'm linking it into an article so you don't have to look at it if you don't want. It is a spoiler.&lt;/A&gt;&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=140982" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Algorithms/default.aspx">Algorithms</category><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Regular+Expressions/default.aspx">Regular Expressions</category></item><item><title>Examination of regex range validation using lower and upper bound values</title><link>http://weblogs.asp.net/justin_rogers/archive/2004/05/22/139681.aspx</link><pubDate>Sun, 23 May 2004 02:44:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:139681</guid><dc:creator>Justin Rogers</dc:creator><author>Justin Rogers</author><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/justin_rogers/rsscomments.aspx?PostID=139681</wfw:commentRss><comments>http://weblogs.asp.net/justin_rogers/archive/2004/05/22/139681.aspx#comments</comments><description>&lt;P&gt;A programming challenge?&amp;nbsp; Maybe a bit of one.&amp;nbsp; If nothing else it is a neat algorithm and examination of generating capture groups that will handle numbers within ranges.&amp;nbsp; The first posting I did on this I examined the generation of 0 through N ranges and ended with the examination of parsing 0-255 or a byte value.&amp;nbsp; In this posting I examine using a lower bound that is not 0, how many decompositions are required to validate such a range, and a general purpose algorithm for doing so.&lt;/P&gt;
&lt;P&gt;&lt;A id=_73f89485eaf_HomePageDays_DaysList__ctl0_DayItem_DayList__ctl0_TitleUrl href="http://blogs.regexadvice.com/justin_rogers/archive/2004/05/22/1147.aspx"&gt;0 through N ranges are interesting, but what about M through N ranges.&lt;/A&gt;&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=139681" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Algorithms/default.aspx">Algorithms</category><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Regular+Expressions/default.aspx">Regular Expressions</category></item><item><title>Generic, Cancellable, Asynchronous operations?  Yeah, I'll blog about that.</title><link>http://weblogs.asp.net/justin_rogers/archive/2004/05/22/139649.aspx</link><pubDate>Sun, 23 May 2004 00:57:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:139649</guid><dc:creator>Justin Rogers</dc:creator><author>Justin Rogers</author><slash:comments>9</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/justin_rogers/rsscomments.aspx?PostID=139649</wfw:commentRss><comments>http://weblogs.asp.net/justin_rogers/archive/2004/05/22/139649.aspx#comments</comments><description>&lt;P&gt;Just code today my friends.&amp;nbsp; The design is simple, create a framework that allows running an asynchronous delegate on the thread pool in a manner where it can be cancelled and any exceptions can be handled.&amp;nbsp; We use the same BeginInvoke/EndInvoke model as the rest of the asynchronous programming models under the framework.&amp;nbsp; Our generic classes allow for the creation of a new generic asynchronous result object for each piece of work we want to do.&amp;nbsp; To fully define a generic async operation we need to specify some from of input, the type of the output, and we can even strongly type the async state object.&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;ar = GenericCancellableOperation&amp;lt;RegexInput, int, Match&amp;gt;.BeginInvoke(&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; new RegexInput(regex, "555"),&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; new GenericWorkDelegate&amp;lt;Match, RegexInput&amp;gt;(RegexWorkDelegate),&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; new AsyncCallback(MatchComplete),&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; counter++&lt;BR&gt;);&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P dir=ltr style="MARGIN-RIGHT: 0px"&gt;The above is a sample usage that does the same thing as my previously defined &lt;A href="http://weblogs.asp.net/justin_rogers/archive/2004/05/22/139337.aspx"&gt;asynchronous regular expression runner&lt;/A&gt;.&amp;nbsp; We can no longer specify entire strings of input parameters, so we have to wrap them all in a single object.&amp;nbsp; Here I've used RegexInput to define the Regex and input to match against.&amp;nbsp; We still use the old AsyncCallback model, even though we could strongly type that as well.&amp;nbsp; In fact, BeginInvoke and EndInvoke still use IAsyncResult instead of more strongly typed equivalents.&amp;nbsp; The GenericWorkDelegate will always match the input and return types for the operation generic, basically allowing us to delegate whatever work needs to occur back to your code.&amp;nbsp; It gets wrapped with all of the protective stuff automatically.&amp;nbsp; You still can't run arbitrary code, because any old fool could wrap a try...catch in their delegate and handle the ThreadAbortException that would normally terminate the operation.&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P dir=ltr style="MARGIN-RIGHT: 0px"&gt;using System;&lt;BR&gt;using System.Threading;&lt;/P&gt;
&lt;P dir=ltr style="MARGIN-RIGHT: 0px"&gt;public delegate ReturnType GenericWorkDelegate&amp;lt;ReturnType, InputType&amp;gt;(InputType input);&lt;/P&gt;
&lt;P dir=ltr style="MARGIN-RIGHT: 0px"&gt;public class GenericCancellableOperation&amp;lt;InputType, AsyncStateType, ReturnType&amp;gt; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public class GenericAsynchronousResult : IAsyncResult {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Generic State Parameters&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal AsyncStateType asyncState = AsyncStateType.default;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal InputType input = InputType.default;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal ReturnType output = ReturnType.default;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal GenericWorkDelegate&amp;lt;ReturnType, InputType&amp;gt; workCallback = GenericWorkDelegate&amp;lt;ReturnType, InputType&amp;gt;.default;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Non generic state&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal bool complete = false;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal bool completedSynchronously = false;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal bool cancelled = false;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal ManualResetEvent waitHandle = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal AsyncCallback callback = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal Thread currentThread = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal Exception innerException = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal Object lockObject = new Object();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal GenericAsynchronousResult(InputType input, GenericWorkDelegate&amp;lt;ReturnType, InputType&amp;gt; workCallback, AsyncCallback callback, AsyncStateType state) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.asyncState = state;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.input = input;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.callback = callback;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.workCallback = workCallback;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.waitHandle = new ManualResetEvent(false);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P dir=ltr style="MARGIN-RIGHT: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public object AsyncState { get { return this.asyncState; } }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public bool CompletedSynchronously { get { return this.completedSynchronously; } }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public bool IsCompleted { get { return this.complete; } }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public WaitHandle AsyncWaitHandle { get { return this.waitHandle; } }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public AsyncStateType TrueAsyncState { get { return this.asyncState; } }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public InputType Input { get { return this.input; } }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public ReturnType Output { get { return this.output; } }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public bool Cancel() {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; lock(lockObject) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( this.cancelled || this.complete ) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return false;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.cancelled = true;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( this.currentThread != null ) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.currentThread.Abort();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P dir=ltr style="MARGIN-RIGHT: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.waitHandle.Set();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return true;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal void Complete() {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; lock(lockObject) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( this.complete || this.cancelled ) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.complete = true;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.waitHandle.Set();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( callback != null ) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; callback(this);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P dir=ltr style="MARGIN-RIGHT: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static GenericAsynchronousResult BeginInvoke(&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; InputType input, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GenericWorkDelegate&amp;lt;ReturnType, InputType&amp;gt; workCallback, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; AsyncCallback callback, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; AsyncStateType state)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GenericAsynchronousResult result =&amp;nbsp; new GenericAsynchronousResult(input, workCallback, callback, state);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( !result.complete ) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadPool_WaitCallback), result);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return result;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static void ThreadPool_WaitCallback(object state) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GenericAsynchronousResult result = state as GenericAsynchronousResult;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( result != null &amp;amp;&amp;amp; !result.cancelled ) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; result.currentThread = Thread.CurrentThread;&lt;/P&gt;
&lt;P dir=ltr style="MARGIN-RIGHT: 0px"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; try {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; result.output = result.workCallback(result.input);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } catch (ThreadAbortException) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Thread.ResetAbort();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } catch (Exception exc) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; result.innerException = exc;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } finally {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; result.currentThread = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; result.Complete();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static ReturnType EndInvoke(IAsyncResult ar) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GenericAsynchronousResult result = ar as GenericAsynchronousResult;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( result != null ) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; result.AsyncWaitHandle.WaitOne();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( result.innerException != null ) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw result.innerException;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return result.output;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } else {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new Exception("EndInvoke was called with the wrong async result");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P dir=ltr style="MARGIN-RIGHT: 0px"&gt;I still don't find this as useful as the regex only version.&amp;nbsp; I think adapting the code to the particular asynchronous operation you are working on is most sufficient.&amp;nbsp; In the case of regular expressions, you could even embed the ability to abort the problem within the lexical scanner, thus removing the necessity of thread aborts and exceptions.&amp;nbsp; In fact for something like an interpreter aborting as an embedded instruction is the best way to go about things.&amp;nbsp; For now, we don't have the ability to modify the construction of regular expressions under .NET and we can't embed such abort instructions, so we'll have to live with little hacks.&lt;/P&gt;
&lt;P dir=ltr style="MARGIN-RIGHT: 0px"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=139649" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/CLR+Internals/default.aspx">CLR Internals</category><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Regular+Expressions/default.aspx">Regular Expressions</category><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Whidbey/default.aspx">Whidbey</category></item><item><title>Asynchronous Regular Expressions using the ThreadPool and a cancellation model.</title><link>http://weblogs.asp.net/justin_rogers/archive/2004/05/22/139337.aspx</link><pubDate>Sat, 22 May 2004 07:40:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:139337</guid><dc:creator>Justin Rogers</dc:creator><author>Justin Rogers</author><slash:comments>10</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/justin_rogers/rsscomments.aspx?PostID=139337</wfw:commentRss><comments>http://weblogs.asp.net/justin_rogers/archive/2004/05/22/139337.aspx#comments</comments><description>&lt;P&gt;There are probably numerous ways to shoot holes in this class, but this is a 30 minute attempt at providing an asynchronous framework for running regular expressions.&amp;nbsp; The crux of the model is to allow for cancellation of long-running expressions that might otherwise have a negative impact on your application or web server.&lt;/P&gt;
&lt;P&gt;You need to start with an IAsyncResult implementation that&amp;nbsp;supports the general asynchronous infrastructure.&amp;nbsp; We'll also have a bunch of extra information for the regular expression work, namely an expression and input string.&amp;nbsp; What I've come up with so far supports all of the features I need including cancellation, full reporting of passed in procedures on the async object for later processing of the work item, and fairly decent protection against the internal members controlling the asynchronous operation.&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;public class AsynchronousRegexResult : IAsyncResult {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal object asyncState = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal Regex expression = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal Match match = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal string inputString = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal bool complete = false;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal bool completedSynchronously = false;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal bool cancelled = false;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal ManualResetEvent waitHandle = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal AsyncCallback callback = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal Thread currentThread = null;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal AsynchronousRegexResult(Regex innerExpression, string inputString, AsyncCallback callback, object state) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.asyncState = state;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.expression = innerExpression;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.inputString = inputString;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.callback = callback;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( this.expression == null || this.inputString == null ) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.complete = true;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.completedSynchronously = true;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.waitHandle = new ManualResetEvent(this.completedSynchronously);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public object AsyncState { get { return this.asyncState; } }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public bool CompletedSynchronously { get { return this.completedSynchronously; } }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public bool IsCompleted { get { return this.complete; } }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public WaitHandle AsyncWaitHandle { get { return this.waitHandle; } }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Regex Expression { get { return this.expression; } }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string Input { get { return this.inputString; } }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Match Result { get { return this.match; } }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public bool Cancel() {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( this.cancelled || this.complete ) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return false;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.cancelled = true;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( this.currentThread != null ) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.currentThread.Abort();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return true;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; internal void Complete() {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.complete = true;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.waitHandle.Set();&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( callback != null ) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; callback(this);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P dir=ltr&gt;Three additional methods are needed to make this work.&amp;nbsp; First, we need a BeginInvoke to launch our operation into the thread pool and an EndInvoke to retrieve the results.&amp;nbsp; We don't really need the EndInvoke, but it builds in semantics for waiting on results if they aren't already available.&amp;nbsp; Finally, the ThreadPool_WaitCallback will be the protected method that enables the true cancellation semantics and the ability to run our expressions.&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P dir=ltr&gt;using System;&lt;BR&gt;using System.Threading;&lt;BR&gt;using System.Text.RegularExpressions;&lt;/P&gt;
&lt;P dir=ltr&gt;public sealed class AsynchronousRegex {&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Removed result class for brevity, but it is a public nested class.&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static IAsyncResult BeginInvoke(Regex innerExpression, string inputString, AsyncCallback callback, object state) {&lt;BR&gt;#if DEBUG&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine("AsynchronousRegex.BeginInvoke::Enter");&lt;BR&gt;#endif&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; AsynchronousRegexResult result = new AsynchronousRegexResult(innerExpression, inputString, callback, state);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( !result.complete ) {&lt;BR&gt;#if DEBUG&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine("AsynchronousRegex.BeginInvoke::ThreadPool Queue");&lt;BR&gt;#endif&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadPool_WaitCallback), result);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;#if DEBUG&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine("AsynchronousRegex.BeginInvoke::Leave");&lt;BR&gt;#endif&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return result;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static void ThreadPool_WaitCallback(object state) {&lt;BR&gt;#if DEBUG&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine("AsynchronousRegex.ThreadPool_WaitCallback::Enter");&lt;BR&gt;#endif&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; AsynchronousRegexResult result = state as AsynchronousRegexResult;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( result != null &amp;amp;&amp;amp; !result.cancelled ) {&lt;BR&gt;#if DEBUG&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine("AsynchronousRegex.ThreadPool_WaitCallback::Setting Current Thread");&lt;BR&gt;#endif&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; result.currentThread = Thread.CurrentThread;&lt;BR&gt;#if DEBUG&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine("AsynchronousRegex.ThreadPool_WaitCallback::Gathering Match");&lt;BR&gt;#endif&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; try {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; result.match = result.expression.Match(result.inputString);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } catch (ThreadAbortException) {&lt;BR&gt;#if DEBUG&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine("AsynchronousRegex.ThreadPool_WaitCallback::Thread Aborted, Resetting");&lt;BR&gt;#endif&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Thread.ResetAbort();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } finally {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; result.currentThread = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;#if DEBUG&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine("AsynchronousRegex.ThreadPool_WaitCallback::Completing Asynchronous Result");&lt;BR&gt;#endif&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; result.Complete();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;#if DEBUG&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine("AsynchronousRegex.ThreadPool_WaitCallback::Leave");&lt;BR&gt;#endif&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static Match EndInvoke(IAsyncResult ar) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; AsynchronousRegexResult result = ar as AsynchronousRegexResult;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( result != null ) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; result.AsyncWaitHandle.WaitOne();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return result.match;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } else {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new Exception("EndInvoke was called with the wrong async result");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P dir=ltr style="MARGIN-RIGHT: 0px"&gt;As mentioned this class is not 100% thread-safe, but will work for the most part.&amp;nbsp; I ran it for a couple of hours and didn't run into any troubles.&amp;nbsp; Not a multi-threaded system though so concurrent access issues wouldn't surface easily (context switching might, but in most cases no).&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=139337" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/justin_rogers/archive/tags/Regular+Expressions/default.aspx">Regular Expressions</category></item></channel></rss>