August 2003 - Posts
Back in June I posted a cryptic little entry that highlighted a potential issue that can arise when displaying user input.
http://weblogs.asp.net/dneimke/posts/8566.aspx
By now we all know that, when rendering user input to the browser that it needs to be HtmlEncoded right... but, what about if you need to display user input into a TextBox? HtmlEncoding it will make it unreadable and (as per my initial post) doing nothing with it will leave you exposed if the user entered something like:
</TEXTAREA><SCRIPT>self.location = 'raceyRhonda.com'</SCRIPT>
My solution to this problem is to emit the user input into a client-side variable and then load it into the TextBox at runtime. Here is a silly demo the explains what I'm blabbing about:
************ WEB FORM **************** <HTML><body> <form id="Form1" method="post" runat="server"> <P> Enter an expression and it will be emitted into the Textbox on PostBack... <BR> <asp:TextBox id="newTestTextBox" runat="server" TextMode="MultiLine" Rows="5" Columns="40"></asp:TextBox> <asp:Button id="testButton" runat="server" Width="72px" Text="Test" /> </P> <P> <HR width="100%" SIZE="1"> </P> <P>Your pattern is: <BR> <asp:TextBox id="outputTextBox" runat="server" Width="504px" /> <BR> <asp:Label id="outputLabel" runat="server"></asp:Label></P> </form> </body></HTML> ************ CODEBEHIND ************** private void testButton_Click(object sender, System.EventArgs e) { string source = CleanString( newTestTextBox.Text ) ; EmitLoadScript( source ) ; outputLabel.Text = Server.HtmlEncode( newTestTextBox.Text ) ; } private string CleanString( string s ) { string tmp = s ; if( tmp.Trim().Length > 0 ) { tmp = Regex.Replace( tmp, @"(?'cleanItem'[\\\/'""])", "\\${cleanItem}" ).Trim() ; } return tmp ; } private void EmitLoadScript( string s ) { StringBuilder sb = new StringBuilder() ; sb.AppendFormat( @"{0}<script>{0}", Environment.NewLine ) ; sb.Append( @"document.getElementById( """ ) ; sb.AppendFormat( @"{0}"" ).value =""{1}"" ;", outputTextBox.ClientID, s ) ; sb.AppendFormat( "{0}</script>{0}", Environment.NewLine ) ; Page.RegisterStartupScript( "populateTB", sb.ToString() ) ; }
Just thought that I'd mention that RegexLib.com has received 10 new patterns this week. Here's a couple of interesting titbits:
There was a pattern added that matches HTML Color strings:
http://www.regexlib.com/REDetails.aspx?regexp_id=372
A regex posted to the "Dates and Times" category only 4 days ago has already received 8 user comments. Take a look at how user comments are helping to evolve stronger, better tested expressions here:
http://www.regexlib.com/REDetails.aspx?regexp_id=369
Overall, it appears that the addition of the Rss feed has increased the activity and participation on the site. You can subscribe to the RegexLib.com feed here:
http://www.regexlib.com/Rss.aspx
I've just uploaded the newest version of the ShowUsYourCode Dhtml Calendar. This cross-browser started its life over 2 years ago and has evolved into quite a slick unit. The latest version incorporates some UI/Css related changes that were put forward by one of its users - Caitlin Fegan.
You can see a working demo of the calendar here:
http://www.flws.com.au/CalendarDemo/DhtmlCalendar.html
... and, you can download the .zip'ped bits here:
http://www.flws.com.au/CalendarDemo/CalendarDemo.zip
Feel free to use it in your projects but please, if you create any cool stylesheets for it, please, please send them to me :-)
I've made a couple of alterations to the opening tag regex.
I've changed the non-capturing group that previously grouped attributes to use Atomic Grouping (?>...) so that states are not saved and therefore reducing any uneccessary backtracking. I've also added a negative lookahead assertion at the beginning of that group so that, if the ending tag is found the whole group will fail and I can step out of the group immediately. This also allows me to remove the lazy (...)*? quantifer at the end of the group and allow it to become (...)*
The entire pattern now looks like this:
(?'openTag'<)
\s*?
(?'tagName'\??\w+)
(?>
(?!=[\/\?]?>)
\s*?
(?'attribName'\w+)
(?:\s*(?'attribSign'=)\s*)
(?'attribValue'
(?:\'[^\']*\'|\"[^\"]*\"|\w+)
)
)*
\s*?
(?'closeTag'[\/\?]?>)
Or, rendered as a single string...
(?'openingTag'<)\s*?(?'tagName'\??\w+)(\s*?(?>(?!=[\/\?]?>)(?'attribName'\w+)(?:\s*(?'attribSign'=)\s*)(?'attribValue'(?:\'[^\']*\'|\""[^\""]*\""|\w+))))*\s*?(?'closeTag'[\/\?]?>)
I was just chatting to Thomas about RegexSnippets and how I use it to test my regex's. I think that most people haven't cottoned-on to the fact that you can write test modules within RegexSnippets itself. To use the code IDE do the following:
You can also save code snippets from within the code IDE by selecting File | Save As. The code snippet gets saved into the "Templates" list in the code IDE.
The most common way of using the code IDE is to generate patterns from the Main Form and then, when you've got the pattern working you can right click in the "Pattern" textbox and choose "Generate Template"; this will copy your current regex and source into a pre-defined Template. You can also create your own Templates by editing the Xml configuration file in "\My Documents\RegexSnippets\Templates.xml".
All of this stuff is pretty much covered in the Help | Readme file.
While fiddling around in RegexSnippets tonight I concocted this regex to match opening tags and to capture the various elements:
(?'openTag'<)
\s*?
(?'tagName'\??\w+)
(?:
\s*?
(?'attribName'\w+)
(?:\s*(?'attribSign'=)\s*)
(?'attribValue'
(?:\'[^\']*\'|\"[^\"]*\"|\w+)
)
)*
\s*?
(?'closeTag'[\/\?]?>)
...and here is a script that I wrote to test it with:
using System ;
using System.Text.RegularExpressions ;
namespace RegexSnippets.Tests
{
public class Foo
{
public static void Main()
{
string source = @"<A href="foo"><TD><A> <TABLE id=1 foo="bar">" ;
string pattern = @"(?'openTag'<)\s*?(?'tagName'\??\w+)(\s*?(?'attribute'(?'attribName'\w+)(?:\s*(?'attribSign'=)\s*)(?'attribValue'(?:\'[^\']*\'|\"[^\"]*\"|\w+))))+\s*?(?'closeTag'[\/\?]?>)" ;
Regex re = new Regex(
pattern,
RegexOptions.IgnoreCase|RegexOptions.Multiline|RegexOptions.Singleline
) ;
for( Match m = re.Match( source ); m.Success; m = m.NextMatch() )
{
Console.WriteLine( "Open tag = {0}", m.Groups["openTag"].Value ) ;
Console.WriteLine( "Tagname = {0}", m.Groups["tagName"].Value ) ;
if( m.Groups["attribName"].Success )
{
for( int i = 0; i < m.Groups["attribName"].Captures.Count; i++ ) {
Console.WriteLine( "Attrib Name = {0}", m.Groups["attribName"].Captures[i].Value ) ;
Console.WriteLine( "Attrib Sign = {0}", m.Groups["attribSign"].Captures[i].Value ) ;
Console.WriteLine( "Attrib Value = {0}", m.Groups["attribValue"].Captures[i].Value ) ;
}
}
Console.WriteLine( "Close tag = {0}", m.Groups["closeTag"].Value ) ;
Console.Write( "{0}**********************************{0}", Environment.NewLine ) ;
}
Console.ReadLine() ;
}
}
}
Blogging about mark-up is difficult, I often try to do it with mixed success. I've been using Word to transfer the colorized mark-up from VS.NET into my blog but, often it will complain about Word's xml formatting. The new “Word Clean“ function in the .Text blog admin tool not only removes the errant xml metadata but, oftentimes it will remove all coloring!
A good way to add colorized markup to a blog post is to use the MarkItUp.com mark-up colorizer:
http://www.markitup.com/Product/Version2.asp
Paste raw mark-up into the Textbox and press “MarkItUp”. Checking the checkbox will force the tool to attempt attribute colorization. Once the mark-up has been colorized just copy and paste the result into the blogging tool.
The other day I was struggling to come to terms with how to perform aggregate queries on a DataTable. I was able to create calculated columns to display calculated data but, I couldn’t work out how to return aggregated data from a query over a DataTable.
Well that all changed today while reading Greg Low’s notes from the recent Australian Tech-Ed. Basically you just use the Compute method of the DataTable – here’s a little demo that will run a LIKE query over a list of names (using the characters that you enter in the textbox followed by a wildcard):
// Compute documentation
http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemDataDataTableClassComputeTopic.asp?frame=true
// Expression Syntax
http://msdn.microsoft.com/library/en-us/cpref/html/frlrfsystemdatadatacolumnclassexpressiontopic.asp?frame=true
// WebForm
<form id="Form1" method="post" runat="server">
<asp:DataGrid id="namesGrid" runat="server" />
<P>
<HR width="100%" SIZE="1">
<asp:TextBox id="entryTextBox" runat="server"></asp:TextBox>
<asp:Button id="getResultsButton" runat="server" Text="Get Count" />
</P>
<P>
<asp:Label id="resultLabel" runat="server"></asp:Label>
</P>
</form>
// Codebehind
private void Page_Load(object sender, System.EventArgs e)
{
if(!IsPostBack)
{
DataTable dt = GetData() ;
namesGrid.DataSource = dt.DefaultView ;
namesGrid.DataBind() ;
}
}
private DataTable GetData()
{
DataTable dt = new DataTable("test") ;
DataColumn dc = new DataColumn("Name", typeof(string)) ;
dt.Columns.Add(dc) ;
string[] names = new string[] {"darren", "peter", "robin", "phil", "wayne", "rob", "doug"} ;
for(int i = 0; i
{
DataRow dr = dt.NewRow() ;
dr["Name"] = names[i] ;
dt.Rows.Add(dr) ;
}
return dt ;
}
private void getResultsButton_Click(object sender, System.EventArgs e)
{
DataTable dt = GetData() ;
namesGrid.DataSource = dt.DefaultView ;
namesGrid.DataBind() ;
int countOfName = (int) dt.Compute("Count(Name)", "Name Like '" + entryTextBox.Text + "*'") ;
resultLabel.Text = countOfName.ToString() + " results match that query." ;
}
Today one of the guys and I were having a conversation about "stuff"; not particularly interesting or relevant but, nonetheless it was "stuff". Now this was your typical bored-nerd conversation, you know the one:
If Me.IsThirsty OrElse Me.IsHungry Then
Me.Goto(Fridge)
Dim coll As Foods = Me.CurrentLocation.GetContents()
Dim i As Integer
For Each f As Food In coll
Me.Consume(f.RawContent)
If i > 10 Then : Me.Burp() : End If
i += 1
Next
End If
The main difference between this senseless conversation and all of the other senseless conversations is that we were "psuedo-ing" in different languages. He was "psuedo-ing" in VB while I was "psuedo-ing" in some wierd, as yet uninvented version of C#.
Now, if you happpen to find yourself having a mixed context conversation then, you'd better keep this link handy ;-)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsintro7/html/vxgrflanguageequivalents.asp
More Posts
Next page »