tag:blogger.com,1999:blog-3999144232845040362024-02-20T01:07:29.032-08:00Reusable CodeASP and PHP code that you can use and re-use. Practical examples for real-world programming, under a Creative Commons license.Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.comBlogger81125tag:blogger.com,1999:blog-399914423284504036.post-72789617787157558452022-08-24T21:07:00.001-07:002022-08-24T21:07:13.995-07:00Morse Code Library<p>Morse code has been on my mind every now and then for the past several years. I don't write as much code as I used to since I left the software development industry, but today I decided it was time to write functions to encode and decode morse.</p><p>First, let's define an array to map the encodings for each character.</p><p style="text-align: left;"></p><ol style="text-align: left;"><li><span style="font-family: courier;">$morse = array(</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>" " => "/",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"A" => ".-",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"B" => "-...",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"C" => "-.-.",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"D" => "-..",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"E" => ".",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"F" => "..-.",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"G" => "--.",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"H" => "....",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"I" => "..",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"J" => ".---",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"K" => "-.-",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"L" => ".-..",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"M" => "--",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"N" => "-.",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"O" => "---",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"P" => ".--.",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"Q" => "--.-",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"R" => ".-.",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"S" => "...",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"T" => "-",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"U" => "..-",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"V" => "...-",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"W" => ".--",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"X" => "-..-",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"Y" => "-.--",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"Z" => "--..",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"0" => "-----",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"1" => ".----",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"2" => "..---",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"3" => "...--",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"4" => "....-",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"5" => ".....",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"6" => "-....",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"7" => "--...",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"8" => "---..",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"9" => "----.",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"." => ".-.-.-",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"," => "--..--",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"?" => "..--..",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"'" => ".----.",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"!" => "-.-.--",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"/" => "-..-.",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"(" => "-.--.",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>")" => "-.--.-",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"&" => ".-...",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>":" => "---...",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>";" => "-.-.-.",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"=" => "-...-",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"+" => ".-.-.",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"-" => "-....-",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"_" => "..--.-",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"\"" => ".-..-.",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"$" => "...-..-",</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>"@" => ".--.-.",</span></li><li><span style="font-family: courier;">);</span></li></ol><p></p><div>This covers almost all possible morse characters, with the exception of accented letters.</div><div><br /></div><div>Next, we need a function to encode messages.</div><div><br /></div><div><div><ol style="text-align: left;"><li><span style="font-family: courier;">function morseEncodeMessage($message)</span></li><li><span style="font-family: courier;">{</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>global $morse;</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>$result = "";</span></li><li><span style="white-space: pre;"><span style="font-family: courier;"> </span></span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>for ($i = 0; $i <= strlen($message) - 1; $i++)</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>{</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>$character = strtoupper(substr($message, $i, 1));</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>$result .= (array_key_exists($character, $morse) ? $morse[$character] : "........") . " ";</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>}</span></li><li><span style="white-space: pre;"><span style="font-family: courier;"> </span></span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>$result = rtrim($result);</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>return $result;</span></li><li><span style="font-family: courier;">}</span></li></ol></div></div><div>We're looping through the message, one character at a time. Lowercase characters are turned into uppercase characters. We check the global array to see if there's a corresponding key, and if so we get the value associated with that key. If the character can't be found, we convert it to a series of eight dots to indicate that an error has occurred. Each encoded character is separated by a space; an extra trailing space is removed before we return the result. Spaces between words are turned into forward slashes.</div><div><br /></div><div>Now we need a way of decoding messages.</div><div><br /></div><div><div><ol style="text-align: left;"><li><span style="font-family: courier;">function morseDecodeMessage($message)</span></li><li><span style="font-family: courier;">{</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>global $morse;</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>$result = "";</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>$characters = explode(" ", $message);</span></li><li><span style="white-space: pre;"><span style="font-family: courier;"> </span></span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>foreach ($characters as &$character)</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>{</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>$result .= in_array($character, $morse, true) ? array_search($character, $morse, true) : "ERROR";</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>}</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>unset($character);</span></li><li><span style="white-space: pre;"><span style="font-family: courier;"> </span></span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>return $result;</span></li><li><span style="font-family: courier;">}</span></li></ol></div></div><div>We start by splitting the encoded message into an array, using the spaces between each letter as the separator. Then we loop through the local array and check the global array for each value. If the value is found, we retrieve the key, otherwise we indicate that an error has occurred.</div><div><br /></div><div>Finally, let's write a unit test to make sure our code is working properly.</div><div><br /></div><div><div><ol style="text-align: left;"><li><span style="font-family: courier;">function morseTest($message)</span></li><li><span style="font-family: courier;">{</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>$testInput = $message;</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>echo "Input: " . strtoupper($testInput) . "\n";</span></li><li><span style="white-space: pre;"><span style="font-family: courier;"> </span></span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>$testEncoded = morseEncodeMessage($testInput);</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>echo "Encoded: " . $testEncoded . "\n";</span></li><li><span style="white-space: pre;"><span style="font-family: courier;"> </span></span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>$testDecoded = morseDecodeMessage($testEncoded);</span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>echo "Decoded: " . $testDecoded . "\n";</span></li><li><span style="white-space: pre;"><span style="font-family: courier;"> </span></span></li><li><span style="font-family: courier;"><span style="white-space: pre;"> </span>echo "Result: Test " . ($testDecoded == strtoupper($testInput) ? "successful" : "failed") . "!\n";</span></li><li><span style="font-family: courier;">}</span></li></ol></div></div><div>Nothing too complicated. Display the message before encoding, encode the message, display the encoded message, decode the message, display the decoded message, and compare the decoded message with the original.</div><div><br /></div><div>If we execute the following:</div><div><span style="font-family: courier;">morseTest("Hello world!");</span></div><div><span style="font-family: courier;"><br /></span></div><div>We get this result:</div><div><div><span style="font-family: courier;">Input: HELLO WORLD!</span></div><div><span style="font-family: courier;">Encoded: .... . .-.. .-.. --- / .-- --- .-. .-.. -.. -.-.--</span></div><div><span style="font-family: courier;">Decoded: HELLO WORLD!</span></div><div><span style="font-family: courier;">Result: Test successful!</span></div></div><div><br /></div>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-64143249499596183192018-05-26T19:21:00.000-07:002018-05-26T19:21:13.360-07:00Temperature Conversion RevisitedI recently completed another ASP.NET project and learned about the app_code folder, which lets you share code between pages. It's slightly similar to the #include directive in Classic ASP, but a lot more structured. I couldn't find much good documentation on it, so most of what I've learned has been through experimentation.<br />
Any files placed into the app_code folder are automatically available from any page in your web application, so you can write: <code>myNamespace.myClass.myFunction(someVariable)</code> and the magic will happen. Alternatively, you can add <code>Imports myNamespace.myClass</code> in the top of your page and call <code>myFunction</code> without all the prefixing.<br />
Though I'm still not a big fan of ASP.NET, this app_code thing is pretty slick and it's inspired me to write more reusable code. I had previously written a collection of functions for temperature conversion, which I've since grown unhappy with after reading Code Complete 2.0 by Steve McConnell because I named my functions like this: <code>CelsiusToFahrenheit</code>, instead of like this: <code>FahrenheitFromCelsius</code>.<br />
I had been planning to write more conversion functions for various units of measurement, but was never satisfied enough with how it was turning out to make it publically available. Besides learning to appreciate ASP.NET, I'm also learning to appreciate object-oriented programming. This whole namespace/class combination with app_code seems to be appropriately suited for doing unit of measurement conversion.<br />
So here's my plan. I've defined a namespace called UOM, which is the manufacturing industry standard abbreviation for unit of measure. Each type of measurement will be a class: temperature, distance, volume, mass, etc. Each class will accept string input so that you can specify both the numeric quantity and the unit of measure simultaneously. The class will use the specified unit of measure to convert values to a common unit of measure, and be able to return values in any equivalent unit of measure.<br />
<h3>
VB.NET</h3>
<ol>
<li><code>Dim inside as Temperature</code></li>
<li><code>inside = New Temperature("10 C")</code></li>
<li><code>Response.Write(inside.getFahrenheit) ' Displays "50"</code></li>
</ol>
And so I proudly announce the release of the first installment in the UOM namespace: UOM.Temperature, which handles Celsius, Delisle, Fahrenheit, Kelvin, Newton, Rankine, Réaumur, and Rømer temperature scales.<br />
<a href="http://snipplr.com/view/53332/temperature-class/">Download the VB.NET source code for UOM.Temperature from Snipplr.com</a>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-85611155514330530862011-09-20T10:18:00.000-07:002011-09-20T10:40:16.947-07:00Force SSL in VB.NETToday I'm wrapping up a project to convert an existing web site to use SSL communication only. This required adding HTTPS detection in various places to prevent mixed-content errors. I'm not entirely happy with my solution for that yet, so I'm not going to go into that right now.<br /><br />What I do want to talk about is actually forcing the user over to HTTPS once your site is SSL-ready. The code I had used for many years on classic ASP sites was not working reliably; it would redirect, but to the home page instead of the page you tried to access.<br /><br />ASP.NET has beefed up the Request object with some additional information we didn't have back in the old days (Request.IsSecureConnection and Request.Url). We also have a new way of including our function libraries, the App_Code folder.<br /><br /><ol><li><code>NameSpace myApplication</code></li><li><code> Public Class myLibrary</code></li><li><code> Public Shared Sub ForceSSL()</code></li><li><code> If Not System.Web.HttpContext.Current.Request.IsSecureConnection Then</code></li><li><code> System.Web.HttpContext.Current.Response.Redirect(System.Web.HttpContext.Current.Request.Url.AbsoluteUri.Replace("http://", "https://"))</code></li><li><code> End If</code></li><li><code> End Sub</code></li><li><code> End Class</code></li><li><code>End NameSpace</code></li></ol><br /><br />Then from each page on the site I import my custom library and run the subroutine:<br /><br /><ol><li><code>Imports myApplication.myLibrary</code></li><li><code></code></li><li><code>Sub Page_Load(sender as Object, e as EventArgs)</code></li><li><code> ForceSSL()</code></li><li><code> 'Rest of code goes here...</code></li><li><code>End Sub</code></li></ol><br /><br />Supposedly there's a way to do this without code by modifying some settings in <abbr title="Internet Information Server">IIS</abbr>, but I didn't have any success with that. The particular situation I'm dealing with has some fairly severe cohesion/coupling issues with certain pages being accessed from different subdomains.<br /><br /><a href="http://snipplr.com/view/58863/force-ssl/">Download the VB.NET source code for ForceSSL from Snipplr.com</a>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-12015648699188096022011-05-10T17:59:00.001-07:002011-05-10T18:14:08.242-07:00Temperature Conversion Revisited<p>I recently completed another ASP.NET project and learned about the app_code folder, which lets you share code between pages. It's slightly similar to the #include directive in Classic ASP, but a lot more structured. I couldn't find much good documentation on it, so most of what I've learned has been through experimentation.</p><p>Any files placed into the app_code folder are automatically available from any page in your web application, so you can write: <code>myNamespace.myClass.myFunction(someVariable)</code> and the magic will happen. Alternatively, you can add <code>Imports myNamespace.myClass</code> in the top of your page and call <code>myFunction</code> without all the prefixing.</p><p>Though I'm still not a big fan of ASP.NET, this app_code thing is pretty slick and it's inspired me to write more reusable code. I had previously written a collection of functions for temperature conversion, which I've since grown unhappy with after reading <a href="http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/ref=sr_1_3?ie=UTF8&qid=1305076400&sr=8-3">Code Complete 2.0</a> by <a href="http://www.stevemcconnell.com/">Steve McConnell</a> because I named my functions like this: <code>CelsiusToFahrenheit</code>, instead of like this: <code>FahrenheitFromCelsius</code>.</p><p>I had been planning to write more conversion functions for various units of measurement, but was never satisfied enough with how it was turning out to make it publically available. Besides learning to appreciate ASP.NET, I'm also learning to appreciate object-oriented programming. This whole namespace/class combination with app_code seems to be appropriately suited for doing unit of measurement conversion.</p><p>So here's my plan. I've defined a namespace called UOM, which is the manufacturing industry standard abbreviation for unit of measure. Each type of measurement will be a class: temperature, distance, volume, mass, etc. Each class will accept string input so that you can specify both the numeric quantity and the unit of measure simultaneously. The class will use the specified unit of measure to convert values to a common unit of measure, and be able to return values in any equivalent unit of measure.</p><h3>VB.NET</h3><ol><li><code>Imports UOM</code></li><li><code></code></li><li><code>Dim outside as Temperature</code></li><li><code>outside = New Temperature("10 C")</code></li><li><code>Response.Write(outside.getFahrenheit) 'Displays "50"</code></li></ol><p>And so I proudly announce the release of the first installment in the UOM namespace: UOM.Temperature, which handles Celsius, Delisle, Fahrenheit, Kelvin, Newton, Rankine, Réaumur, and Rømer temperature scales.</p><p><a href="http://snipplr.com/view/53332/temperature-class/">Download the VB.NET source code for UOM.Temperature from Snipplr.com</a></p>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-9837270270754197452010-09-14T17:01:00.000-07:002010-09-14T18:00:45.770-07:00Scalable Site Structure<p>If you've been developing web sites for a few years, you've probably developed a lot of sites with a structure similar to the following:</p><ul><li>/css/</li><li>/images/</li><li>/scripts/</li><li>index.php</li><li>about.php</li><li>products.php</li></ul><p>One of my colleagues likes to keep the root directory as clean as possible, so his site structures look like this:</p><ul><li>/content/about.php</li><li>/content/products.php</li><li>/common/</li><li>/images/</li><li>index.php</li></ul><p>Which I find slightly irritating because I prefer to keep my <abbr title="Cascading Style Sheets">CSS</abbr> separate from my JavaScript, and the /content/ folder is just taking the mess from one place and moving it to another.</p><p>Of course, the Holy Grail of site structures is to have clean <abbr title="uniform resources locator">URL</abbr>s like this:</p><ul><li>/about/</li><li>/css/</li><li>/images/</li><li>/products/</li><li>/scripts/</li><li>index.php</li></ul><p>If you have a dynamic site, this is easily achieved using mod_rewrite, so /about/ becomes index.php?page=about, but sometimes the client doesn't want to pay for a dynamic site. In that case we use the Poor Man's Clean URLs™ wherein we actually create the /about/ and /products/ folders and put an index.php file in each with the static content. The PHP is then only really used to include a header, footer, navigation, etc.</p><p>As a site grows, performance and scalability become a (greater) concern. Popular site speed analysis tools often recommend using a content distribution network. Whether you outsource this or try to do it in-house, it sounds like a lot of work.</p><p>I hadn't had the privilege of working on a site that experienced enough traffic to be concerned about scalability until earlier this year. The company was running a national television commercial. They had hired another company to develop a micro-site on a separate server for the campaign, but viewers were being directed to the regular corporate site where a gigantic ad enticed them to visit the micro-site. If you're shaking your head right now, me too. The corporate web server was going down almost daily.</p><p>The web statistics package indicated that the most downloaded files were the product videos. I still don't know why they aren't using <a href="http://www.youtube.com">YouTube</a> or <a href="http://vimeo.com">Vimeo</a> for this purpose. On a hunch, I copied the video files to the micro-site's web server and changed all the links. They experienced zero downtime after that.</p><p>This experience made me think about how to build scalability into a site from the beginning. Something in the back of my mind twigged a memory of reading something about <a href="http://code.google.com/speed/page-speed/docs/request.html">serving static content from a cookieless domain</a>. Cookies aside, it turns out that serving content from multiple subdomains has certain <a href="http://www.askapache.com/htaccess/apache-speed-subdomains.html">performance advantages</a>.</p><p>Any discussion of clean URLs would not be complete without mentioning www.example.com vs. example.com. Dropping the www seems to be the "cool" thing to do, but my personal feeling is that www.example.com is more descriptive of what you will find there. The mail server is mail.example.com, so the web server should be www.example.com.</p><p>So here's the site structure I'm planning to use for future projects:</p><ul><li>/css/ - css.example.com</li><li>/images/ - images.example.com</li><li>/images/logos/ - images.example.com/logos/</li><li>/images/products/ - images.example.com/products/</li><li>/js/ - js.example.com</li><li>/www/ - www.example.com</li><li>/www/about/ - www.example.com/about/</li><li>/www/products/ - www.example.com/products/</li><li>/www/index.php - the actual home page</li><li>/index.php - file which redirects to www.example.com</li></ul><p>The subdomains can be hosted from the primary web server while traffic is small, and migrated to dedicated servers when the traffic increases. The URLs to the images, scripts, and stylesheets don't change, so the PHP files don't need to be updated. Use plenty of folders to keep things organized. You can see I made folders at images.example.com to keep the logos separate from product pictures. If there will be a lot of pictures for each product, I would make folders within the products folder to keep them segregated.</p>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-74374021976386570362010-09-05T13:17:00.000-07:002010-09-10T13:27:54.699-07:00Roman Numerals, Part 4<a href="http://www.blogger.com/profile/03164086700339769547">Keith Alexander</a> of Albuquerque, New Mexico writes:<br /><blockquote>“I like your Roman Numeral library. I needed a function to test for Roman numerals, so I wrote this one.<br /><ol><li><code>// Check to see if the string is a Roman Numeral</code></li><li><code>// NOTE: this doesn't check for fractions, overbars, the Bede "N" (zero) etc.</code></li><li><code>// NOTE: It also doesn't check for a well-formed Roman Numeral.</code></li><li><code>function is_roman_numeral( $roman )</code></li><li><code>{</code></li><li><code> // Strip every non-word character </code></li><li><code> // - A-Z, 0-9, apostrophe and understcore are what's left</code></li><li><code> $roman = preg_replace( "/[^A-Z0-9_']/iu", "", $roman );</code></li><li><code></code></li><li><code> // if it contains anything other than MDCLXVI, then it's not a Roman Numeral</code></li><li><code> $result = preg_match( "/[^MDCLXVI]/u", $roman );</code></li><li><code></code></li><li><code> if( $result )</code></li><li><code> {</code></li><li><code> return FALSE;</code></li><li><code> }</code></li><li><code></code></li><li><code> return TRUE;</code></li><li><code>}</code></li></ol><br />Who knows if blogger is going to show it properly. If not, just contact me and I'll send it you in email or something. Anyway, it's something I wrote in 5 minutes. If you want to add it to your library, modified or otherwise, please feel free.”</blockquote><br />Thanks for writing in Keith, and sorry for the late response. There are two ways to validate a Roman number, using regular expressions like you did, and converting back to an Arabic number (if the conversion fails, it's not a Roman number).<br /><br />I'm not sure about using a regular expression to remove non-word characters. My gut tells me that anything containing such characters should fail validation as a Roman number. Also, I would reverse the match and eliminate the <code>if</code> statement by directly returning the result of the match.<br /><br /><h3>PHP</h3><ol><li><code>function isRoman($roman)</code></li><li><code>{</code></li><li><code> return preg_match("/[MDCLXVI]/u", $roman);</code></li><li><code>}</code></li></ol><br /><h3>ASP</h3><ol><li><code>function isRoman(roman)</code></li><li><code> dim regEx</code></li><li><code> set regEx = new RegExp</code></li><li><code></code></li><li><code> with regEx</code></li><li><code> .IgnoreCase = true</code></li><li><code> .Global = true</code></li><li><code> .Pattern = "[MDCLXVI]"</code></li><li><code> end with</code></li><li><code></code></li><li><code> if regEx.Test(roman) then</code></li><li><code> isRoman = true</code></li><li><code> else</code></li><li><code> isRoman = false</code></li><li><code> end if</code></li><li><code></code></li><li><code> set regEx = nothing</code></li><li><code>end function</code></li></ol><br /><br /><ul><li><a href="http://snipplr.com/view/8104/bigroman/">View ASP implementation on Snipplr</a></li><li><a href="http://snipplr.com/view/8105/bigroman/">View PHP implementation on Snipplr</a></li></ul>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-56224540221017532632010-09-05T10:29:00.001-07:002010-09-10T13:24:00.223-07:00Calculating annual salary for employees paid hourlyLast time I explained how to calculate the annual salary for an employee who is paid by the hour. Today I'm going to show you by writing a function for it, and we'll write one for monthly salary too.<br /><br /><ol><li><code>function annualSalary(someYear, hourlyPay)</code></li><li><code> const hoursPerDay = 8</code></li><li><code> annualSalary = 0</code></li><li><code></code></li><li><code> for i = 1 to 12</code></li><li><code> annualSalary = annualSalary + WorkingDays(someYear, i) * hoursPerDay * hourlyPay</code></li><li><code> next</code></li><li><code>end function</code></li><li><code></code></li><li><code>function monthlySalary(someYear, someMonth, hourlyPay)</code></li><li><code> const hoursPerDay = 8</code></li><li><code> monthlySalary = 0</code></li><li><code></code></li><li><code> monthlySalary = monthlySalary + WorkingDays(someYear, someMonth) * hoursPerDay * hourlyPay</code></li><li><code>end function</code></li></ol><br /><br /><a href="http://snipplr.com/view/40318/calculate-monthly-andor-annual-salary/">View ASP implementation on Snipplr</a>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-52107987898737242762010-09-01T14:18:00.000-07:002010-09-01T14:53:39.560-07:00Number of working days in a month<p>I didn't realize it's been over a year since my last post. Most of the code I've written this past year has been too specialized to be considered useful to anyone outside of my present employer, but this week I was presented with a problem with our Intranet application where the annual salary of employees who are paid hourly was not being calculated correctly. I'm working with the application vendor to get this corrected in the next version, and learned some interesting things about how to calculate this correctly.</p><p>A common formula to calculate annual salary for hourly employees is hourly pay × 40 hours/week × 52 weeks/year. This is very close to accurate, but 365/366 days per year does not divide evenly by 7 days/week.</p><p>A more accurate result can be obtained by multiplying the hourly pay by the number of working hours in a year. One way to calculate this is based on the last day of the year. In a non-leap year, there are 2080 working hours if the last day of the year is a Saturday or Sunday, and 2088 working hours if the last day of the year is a weekday. In the case of a leap year, there are 2080 working hours if the last day of the year is a Sunday, 2088 working hours if the last day of the year is a Saturday or Monday, and 2096 working hours for any other weekday.</p><p>At our company, we work 8 hours each day, so we can calculate the number of working days rather than the number of working hours and multiply by 8 hours/day. Since the number of days per month is variable, I decided to calculate working days per month separately and sum them up for working days per year.</p><br /><ol><li><code>Function WorkingDays(someYear, someMonth)</code></li><li><code> WorkingDays = 0</code></li><li><code></code></li><li><code> For i = 1 To MonthDays(someYear, someMonth)</code></li><li><code> If Weekday(DateSerial(someYear, someMonth, i)) <> 1 And Weekday(DateSerial(someYear, someMonth, i)) <> 7 Then</code></li><li><code> WorkingDays = WorkingDays + 1</code></li><li><code> End If</code></li><li><code> Next</code></li><li><code>End Function</code></li></ol><br /><p>You can take the result and multiply by 8 hours/day to get the number of working hours in a month, and then multiply by the hourly pay to get the monthly salary. The annual working days can be obtained by calling the function in a <code>for i = 1 to 12...next</code> loop, multiplied by 8 hours/day to get the number of working hours in a year, and then multiplied by the hourly pay to get the annual salary.</p><p>We ignore holidays and vacation days since the employee is paid for those as well, though technically vacation pay is accured at 4% so you could subtract vacation days (probably either 10 or 15, depending on number of years of service) and multiply by 1.04 to get an even more accurate amount for annual salary.</p><br /><p><a href="http://snipplr.com/view/39873/number-of-working-days-in-a-month/">View ASP implementation on Snipplr</a>.</p>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-8154535111961010972009-06-06T08:46:00.000-07:002009-06-06T08:51:40.812-07:00Publishing schedule changeAs I mentioned last week, I ran out of code samples that are suitable for publishing. All that remains is code in various states of partial completion. I was trying to avoid this, but have decided I need to change the publishing schedule of this blog from weekly to whenever I have something finished. I have some fairly large projects on the go right now that I need to focus on if I hope to complete them in my own lifetime. I'm not even sure that anyone is ever reading this besides myself as I type it, so I don't expect anyone will be upset by this.Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-26890740822477379302009-05-30T17:22:00.000-07:002009-05-30T17:38:03.025-07:00Dynamic Arrays<p>I have to shamefully admit... I didn't prepare anything for this week. I'd hate to post nothing, so instead I'll post something which I don't consider completely finished yet, but it's far enough along that it probably works just fine.</p><br /><p>Working with arrays in classic ASP is frustrating. I wanted to make it more like working with listbox controls in Visual Basic. Note that I wrote this class before I started learning ASP.NET; I wanted to revamp it to bring it in line with the ArrayList class in VB.NET, but just haven't had time yet. More importantly, I haven't really had reason. All my current projects are in PHP or ASP.NET; I've essentially abandoned classic ASP. But I know there are people out there with classic ASP applications which they can't completely rewrite, so I intend to continue writing classic ASP functions.</p><br /><p>Considering the enormous size of this class, there's no way I'm going to attempt posting it here, but it'll be on Snipplr as usual. Count, Item, and Items are implemented as properties. Subroutines and functions include: Remove, RemoveAll, Add, BinarySearch, Exists, Random, Reverse, Sort (calls QuickSort; also available are BubbleSort, CombSort, ExchangeSort, and SelectionSort), Shuffle, Swap, Sum, and Product.</p><br /><p><a href="http://snipplr.com/view/15412/dynamic-array-class/">View ASP implementation on Snipplr</a></p>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com1tag:blogger.com,1999:blog-399914423284504036.post-3055294496354831362009-05-23T08:06:00.000-07:002009-05-23T08:17:59.136-07:00Prime Numbers<p>Once upon a time I wrote some functions for finding and checking prime numbers. In this library of functions you'll find the following:</p><br /><ul><li>getPrimes() - finds prime numbers up to a specified limit</li><li>isPrime() - checks if a number is prime using modular division against odd numbers</li><li>isPrime2() - checks if a number is prime using modular division against known primes</li><li>primeCount() - counts the number of primes less than or equal to the specified number</li><li>isComposite() - the opposite of prime</li><li>isPrimeSpeedTest() - races isPrime againts isPrime2</li></ul><br /><p>In theory, checking against known primes should be faster than checking against all odd numbers, but it turned out to be slower because I was first finding the primes with getPrimes(). If a list of prime numbers was hardcoded in an array it might be faster for smaller numbers, and then the odd number method could be used for larger numbers.</p><br /><p><a href="http://snipplr.com/view/15252/prime-numbers/">View ASP implementation on Snipplr</a></p>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-72616465032681634362009-05-16T09:36:00.000-07:002009-05-16T09:54:12.116-07:00Chemistry Library<p>This week's code is probably the biggest single release I've ever made. I considered splitting it up into two or three weeks, but that would be too much work. Before we get started, you'll need my <a href="http://reusablecode.blogspot.com/2008/04/proper-case.html">proper case function</a>.</p><br /><p>In this function library, we have three major things going on: look up chemical element symbols by atomic number, look up chemical element names by atomic number, and figure out the electron configuration of an atom given the atomic number.</p><br /><p>For the chemical element names and symbols, I made an array of all the named elements; currently the highest named element is atomic number 111. There are elements with higher atomic numbers that have been discovered, but not yet named. There is also the possibility that more elements may be discovered in the future. To handle both these situations, I wrote code to generate standardized names if the array lookup fails.</p><br /><p>The function(s) for figuring out electron configuration are my favorite. I started with an array of all the subshells in the order they get filled. Then I wrote a function that knows how many electrons can fit in each type of subshell. Finally, I wrote the main function which fills the subshells, taking into account known exceptions to the rules. (e.g. palladium)</p><br /><ul><li><a href="http://snipplr.com/view/15097/chemistry-library/">View ASP implementation on Snipplr</a></li><li><a href="http://snipplr.com/view/15098/chemistry-library/">View PHP implementation on Snipplr</a></li></ul>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-72659216920129266792009-05-09T07:47:00.000-07:002009-05-09T08:00:56.112-07:00Fuel consumption<p>Last November I was at a Service Canada office and picked up a pamphlet called <cite>Fuel Consumption Guide 2007</cite>. Although too old to be relevant (unless you're buying a used car), it contained some formulae for calculating fuel consumption which inspired me to write some code.</p><br /><p>This library of functions is among the longest yet, so I won't be posting the code directly on the blog, but here's a list of the functions included:</p><br /><ul><li>lph() - Calculate fuel consumption rating in litres per 100 kilometres.</li><li>mpg() - Calculate fuel consumption rating in miles per gallon.</li><li>lph2mpg() - Convert miles per (imperial) gallon to litres per 100 kilometres.</li><li>mpg2lph() - Convert litres per 100 kilometres to miles per (imperial) gallon.</li><li>fuelConsumption() - Calculate fuel consumption in litres.</li><li>CO2emissions() - Calculate carbon dioxide emissions in kilograms.</li></ul><br /><ul><li><a href="http://snipplr.com/view/14873/fuel-consumption/">View ASP implementation on Snipplr</a></li><li><a href="http://snipplr.com/view/14874/fuel-consumption/">View PHP implementation on Snipplr</a></li></ul>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-29149635467342617472009-05-02T08:13:00.000-07:002009-05-02T08:23:50.932-07:00Regular Expressions<p>Over the past year, I've posted a lot of code that made use of regular expressions. When used appropriately, they can be very powerful. But regular expressions in ASP are a little more cumbersome than PHP. Wouldn't it be great if ASP had the simplicity of regular expression functions?</p><br /><p>Once again, the source code is too long to post here, so it will only be available on Snipplr. This library of functions includes the following:</p><ul><li>ereg() - case-sensitive regular expression match</li><li>eregi() - case-insensitive regular expression match</li><li>ereg_replace() - case-sensitive regular expression replacement</li><li>eregi_replace() - case-insensitive regular expression replacement</li><li>sql_regcase() - make regular expression for case insensitive match</li></ul><br /><p><a href="http://snipplr.com/view/14646/regular-expressions/">View ASP implementation on Snipplr</a></p>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com1tag:blogger.com,1999:blog-399914423284504036.post-68388933875625584102009-04-25T09:14:00.000-07:002009-04-25T09:25:38.047-07:00Social Insurance Numbers<p>Here in Canada, our equivalent of the Social Security Number is called Social Insurance Number. It serves the same purpose and has the same demands for privacy surrounding it.</p><br /><p>Once again, I won't be posting the full source code on the blog, only on Snipplr, but I will discuss briefly how it works. It consists of three groups of three digits, and is validated using the <a href="http://reusablecode.blogspot.com/2009/03/luhn-algorithm.html">Luhn algorithm</a>. I also do a quick regular expression validation to check for numbers which invalidly begin with an eight: <code>^([1-79]{3})[\-\s]?(\d{3})[\-\s]?(\d{3})$</code>.</p><br /><ul><li><a href="http://snipplr.com/view/14411/social-insurance-numbers/">View ASP implementation on Snipplr</a></li><li><a href="http://snipplr.com/view/14412/social-insurance-numbers/">View PHP implementation on Snipplr</a></li></ul>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-14041110350890346152009-04-18T07:50:00.000-07:002009-04-18T08:14:35.255-07:00Social Security Numbers<p>Assuming that you have a legitimate need to capture social security numbers (human resources app?), you may want to validate and format them consistently. The actual code for both languages combined is a little bit too long to post, so I'll just talk about the algorithm.</p><br /><p>A social security number is a nine-digit number and can be matched with the following regular expression: <code>^\d{3}\-?\d{2}\-?\d{4}$</code>. If it can't pass this test, it's not a valid social security number. However, passing this simple test doesn't guarantee validity, so we need to keep checking.</p><br /><ul><br /><li>No digit group can consist of only zeros, and the first group cannot be 666. We check for these errors with the following regular expression: <code>((000|666)\-?\d{2}\-?\d{4}|\d{3}\-?00\-?\d{4}|\d{3}\-?\d{2}\-?0000</code>.</li><br /><li>Numbers from 987-65-4320 to 987-65-4329 are reserved for use in advertisements, and other previously legitimate numbers have been invalidated because of use in advertisments. We check for these errors with the following regular expression: <code>987\-?65\-?432\d{1}|042\-?10\-?3580|062\-?36\-?0749|078\-?05\-?1120|095\-?07\-?3645|128\-?03\-?6045|135\-?01\-?6629|141\-?18\-?6941|165\-?(16|18|20|22|24)\-?7999|189\-?09\-?2294|212\-?09\-?(7694|9999|219\-?09\-?9999|306\-?30\-?2348|308\-?12\-?5070|468\-?28\-?8779|549\-?24\-?1889)</code></li><br /><li>Last but not least, the first three numbers are never higher than 772 (well, not yet; this could change in the future). For this I used a simple string conversion and numeric comparison.</li><br /></ul><br /><p>The complete, commented source code is available on Snipplr:</p><ul><li><a href="http://snipplr.com/view/14151/social-security-numbers/">View ASP implementation on Snipplr</a></li><li><a href="http://snipplr.com/view/14152/social-security-numbers/">View PHP implementation on Snipplr</a></li></ul><br /><p>Next week we'll head north of the border to my country and see what the Canadian equivalent of the Social Security Number is, and how we can validate them.</p>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com3tag:blogger.com,1999:blog-399914423284504036.post-35312516600826906722009-04-11T07:20:00.000-07:002009-04-11T07:44:05.852-07:00Homeland Security Advisory System<p>Back in 2002, a bunch of bureaucrats decided that the United States needed an advisory system so that all federal departments and agencies could communicate what the current threat condition was using the same definitions. Sounds like a good idea to me.</p><br /><p>The average citizen can see what the current threat condition is by visiting certain government web sites. The web site for the <a href="http://www.dhs.gov">Department of Homeland Security</a> is a good example.</p><br /><p>The Department of Homeland Security also provides a little-known web service which returns the <a href="http://www.dhs.gov/dhspublic/getAdvisoryCondition">threat condition in XML format</a> so that you can do what you want with it. Let's write a function to retrieve and parse this information down to just the threat condition itself.</p><br /><h4>ASP</h4><br /><ol><br /><li><code>function getThreatLevel()</code></li><br /><li><code> dim regEx</code></li><br /><li><code> set regEx = new RegExp</code></li><br /><li><code></code></li><br /><li><code> with regEx</code></li><br /><li><code> .Pattern = ".*\n.*CONDITION=""(.*)"" />"</code></li><br /><li><code> .IgnoreCase = true</code></li><br /><li><code> .Global = true</code></li><br /><li><code> end with</code></li><br /><li><code></code></li><br /><li><code> dim xmlhttp</code></li><br /><li><code> set xmlhttp = Server.CreateObject("Msxml2.ServerXMLHTTP")</code></li><br /><li><code> xmlhttp.open "GET", "http://www.dhs.gov/dhspublic/getAdvisoryCondition", "False"</code></li><br /><li><code> xmlhttp.send</code></li><br /><li><code></code></li><br /><li><code> getThreatLevel = regEx.replace(xmlhttp.responseText, "$1")</code></li><br /><li><code></code></li><br /><li><code> set xmlhttp = nothing</code></li><br /><li><code> set regEx = nothing</code></li><br /><li><code>end function</code></li><br /></ol><br /><p>As is often the case, the PHP version requires a significantly less amount of code.</p><br /><h4>PHP</h4><br /><ol><br /><li><code>function getThreatLevel()</code></li><br /><li><code>{</code></li><br /><li><code> return eregi_replace('.*CONDITION="(.*)" />', '\1', file_get_contents("http://www.dhs.gov/dhspublic/getAdvisoryCondition"));</code></li><br /><li><code>}</code></li><br /></ol><br /><p>So now we have a string that contains just the word "ELEVATED" (or whatever the current threat level is at the moment; it's been at elevated for several years at the time of this writing). What can you do with it? Feed it into a switch statement and display an image is one possibility.</p><br /><ul><li><a href="http://snipplr.com/view/13963/homeland-security-advisory-system/">View ASP implementation on Snipplr</a></li><li><a href="http://snipplr.com/view/13964/homeland-security-advisory-system/">View PHP implementation on Snipplr</a></li></ul>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-23931783221079577862009-04-04T08:08:00.001-07:002009-04-04T08:16:32.650-07:00Min/Max<p>SQL contains a number of <a href="http://msdn.microsoft.com/en-us/library/ms173454.aspx">aggregate functions</a> that can do things like select the largest or smallest number from a set of values. This could be handy in the programming language itself.</p><br /><h4>ASP</h4><ol><li><code>function max(arrNumbers)</code></li><li><code> dim result</code></li><li><code></code></li><li><code> result = arrNumbers(0)</code></li><li><code></code></li><li><code> for each i in arrNumbers</code></li><li><code> if i > result then</code></li><li><code> result = i</code></li><li><code> end if</code></li><li><code> next</code></li><li><code></code></li><li><code> max = result</code></li><li><code>end function</code></li><li><code></code></li><li><code>function min(arrNumbers)</code></li><li><code> dim result</code></li><li><code></code></li><li><code> result = arrNumbers(0)</code></li><li><code></code></li><li><code> for each i in arrNumbers</code></li><li><code> if i < result then</code></li><li><code> result = i</code></li><li><code> end if</code></li><li><code> next</code></li><li><code></code></li><li><code> min = result</code></li><li><code>end function</code></li></ol><br /><p><a href="http://snipplr.com/view/13769/minmax/">View ASP implementation on Snipplr</a></p>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-12101083259001656192009-03-28T08:34:00.000-07:002009-03-28T08:42:15.498-07:00getFileType<p>Last week I showed you how to get the size of a file. This week I'm going to show you how to get the type of a file. This is useful if you want to display an icon or bit of text next to a hyperlink to indicate the file type. Some people like to use this to warn visitors when they link to a PDF file, because PDF readers can take a while to load.</p><br /><h4>ASP</h4><ol><li><code>function getFileType(someFile)</code></li><li><code> dim fs</code></li><li><code></code></li><li><code> set fs = Server.CreateObject("Scripting.FileSystemObject")</code></li><li><code> getFileType = fs.GetExtensionName(Server.MapPath(someFile))</code></li><li><code> set fs = nothing</code></li><li><code>end function</code></li></ol><br /><p>See you next week!</p><br /><p><a href="http://snipplr.com/view/13532/getfiletype/">View ASP implementation on Snipplr</a></p>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-5048842531332518362009-03-21T08:58:00.000-07:002009-03-28T08:40:21.690-07:00getFileSize<p>When you provide a link to a file for the user to download, it's sometimes nice to provide the size of the file so that they know what they're getting themselves into.</p><br /><h4>ASP</h4><ol><li><code>function getFileSize(someFile)</code></li><li><code> dim fs</code></li><li><code> dim file</code></li><li><code></code></li><li><code> set fs = Server.CreateObject("Scripting.FileSystemObject")</code></li><li><code> set file = fs.GetFile(Server.MapPath(someFile))</code></li><li><code></code></li><li><code> getFileSize = FormatFileSize(file.size)</code></li><li><code> set file = nothing</code></li><li><code> set fs = nothing</code></li><li><code>end function</code></li></ol><br /><p>The <code>size</code> property returns the size in bytes, which could be a very large number. As you may have guessed, we're going to write a FormatFileSize function to wrap around it.</p><br /><h4>ASP</h4><ol><li><code>function FormatFileSize(size)</code></li><li><code> dim units</code></li><li><code> dim factor</code></li><li><code></code></li><li><code> units = Array("B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")</code></li><li><code> factor = log(size) \ 7</code></li><li><code></code></li><li><code> FormatFileSize = Round(size / (1024 ^ factor), 2) & units(factor)</code></li><li><code>end function</code></li></ol><br /><p>I think it will be a very, very long time before we reach yottabytes, so this function should withstand the test of time. Next week I'll show you how to get the file type and why you might want that.</p><br /><p><a href="http://snipplr.com/view/13348/getfilesize/">View ASP implementation on Snipplr</a></p>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-53006750111654748682009-03-14T07:36:00.000-07:002009-03-14T07:50:36.852-07:00Soundex<p>This week we're going to write a function to convert letters to their corresponding soundex codes. But wait, there's more! We'll also allow you to pass in an entire string and convert the whole thing. Here's the set up:</p><br /><ol><li><code>function soundex(someString)</code></li><li><code> if len(someString) = 1 then</code></li><li><code> ' code to convert a single character</code></li><li><code> else</code></li><li><code> ' loop through the whole string and convert each character</code></li><li><code> end if</code></li><li><code>end function</code></li></ol><br /><p>Inside the loop, we'll recursively call the soundex function to convert the individual character. Actually, this may not perfectly fit the definition of recursion. The only recursive aspect of it is that the function calls itself, but an entirely different execution path is being followed once inside. But that's good, because we won't have the poor performance that sometimes comes with recursion.</p><br /><p>Once again, the full source code is a little too long to post, so you'll have to grab it from Snipplr:</p><br /><ul><li><a href="http://snipplr.com/view/13119/soundex/">View ASP implementation on Snipplr</a></li><li><a href="http://snipplr.com/view/13120/soundex/">View PHP implementation on Snipplr</a></li></ul>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-26315919223538886032009-03-07T07:33:00.000-08:002009-03-07T07:49:44.157-08:00Luhn Algorithm<p>This week we're writing a function to verify credit card numbers. Credit cards have a check digit which is generated with the <a href="http://en.wikipedia.org/wiki/Luhn_algorithm">Luhn algorithm</a>. The code is too long to post here, but as always it is posted on Snipplr and linked here for your dissemination.</p><br /><ul><li><a href="http://snipplr.com/view/12892/luhn-algorithm/">View ASP implementation on Snipplr</a></li><li><a href="http://snipplr.com/view/12893/luhn-algorithm/">View PHP implementation on Snipplr</a></li></ul>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-14124608927543663592009-02-28T06:09:00.000-08:002009-02-28T06:36:35.182-08:00Phonetic Alphabet<p>It seems to me that most people have trouble remembering the phonetic alphabet (probably myself included). Unless you're a pilot or air traffic controller, it's unlikely that your job requires you to have it memorized. People get by with whatever word comes to mind ("A as in Adam"), but this seems like an opportunity to write some code.</p><br /><p>For maximum reusability, I'm going to write my function to convert individual characters at a time. Looping through the characters of the string will occur outside the function. The function is too long to paste here in its entirety, but it will be posted on Snipplr and linked at the bottom of this entry.</p><br /><p>PHP has key/value arrays where we can specify any keys we want, so we'll declare an array containing all the conversions and use the input to retrieve the correct string from the array. ASP's arrays don't have this flexibility; we could achieve this with a Dictionary scripting object, but I'm concerned about the overhead associated with that. I'm going to use a Select...Case statement (AKA switch statement), but there is a chance that this is actually not any better. I'll leave the determination of this as an exercise to the reader. Also left as an exercise to the reader is the writing of the looping code.</p><br /><ul><li><a href="http://snipplr.com/view/12664/phonetic-alphabet/">View ASP implementation on Snipplr</a></li><li><a href="http://snipplr.com/view/12665/phonetic-alphabet/">View PHP implementation on Snipplr</a></li></ul>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com2tag:blogger.com,1999:blog-399914423284504036.post-12026101006935741372009-02-21T15:48:00.000-08:002010-09-10T13:18:48.780-07:00Add and strip slashes<p>Good programmers know that they can't trust user-inputted data. We do as much as we can to validate and try to prevent bad data from getting into our applications. But there is even some perfectly valid data that can cause trouble, especially when you're dealing with databases. The single apostrophe is a common occurrence and gotcha for the newbies when they discover the tail end of their string didn't make it into the database.</p><br /><p>Our PHP programmer friends have a few different functions at their disposal. Native to PHP are the addslashes() and stripslashes() functions, which basically do what they say. In more common usage these days is the MySQL-native function, mysql_real_escape_string(), which can handle a wider variety of situations. I'm going to go a little bit further and handle the backspace and horizontal tab characters.</p><br /><p>The regular expression we'll be using to add slashes is <code>([\000\010\011\012\015\032\042\047\134\140])</code>, and to remove slashes we'll use <code>\\([\000\010\011\012\015\032\042\047\134\140])</code>. The only difference is the extra pair of slashes at the beginning. These handle, respectively: null, backspace, horizontal tab, new line, carriage return, substitute, double quote, single quote, backslash, and grave accent.</p><br /><ul><li><a href="http://snipplr.com/view/12446/add-and-strip-slashes/">View ASP implementation on Snipplr.</a></li><li><a href="http://snipplr.com/view/40317/add-and-strip-slashes/">View VB.NET implementation on Snipplr</a></li></ul>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0tag:blogger.com,1999:blog-399914423284504036.post-82523978650866622162009-02-14T07:58:00.000-08:002009-02-14T08:10:50.788-08:00htmlspecialchars()<p>If you rigoursly validate your HTML like I do, you've probably seen many times the warning about HTML entities. Inevitably an ampersand makes its way into your code without being properly encoded. It's almost always in a hyperlink where you're trying to pass a QueryString variable or two.</p><br /><p><code>somefile.asp?this=that&blah=meh</code></p><br /><p>That ampersand needs to be encoded as <code>&amp;</code>. Likewise, double quotation marks need to be encoded as <code>&quot;</code> and the greater than and less than symbols need to be encoded as <code>&gt;</code> and <code>&lt;</code> respectively. If you allow users to write things on your web site, then you need a programmatic solution. Our PHP programmer friends have one in their toolbox which we can borrow.</p><br /><ol><li><code>function htmlspecialchars(someString)</code></li><li><code> ' Critical that ampersand is converted first, since all entities contain them.</code></li><li><code> htmlspecialchars = replace(replace(replace(replace(someString, "&", "&"), ">", ">"), "<", "<"), """", """)</code></li><li><code>end function</code></li><li><code></code></li><li><code>function htmlspecialchars_decode(someString)</code></li><li><code> htmlspecialchars_decode = replace(replace(replace(replace(someString, "&", "&"), ">", ">"), "<", "<"), """, """")</code></li><li><code>end function</code></li></ol><br /><p><a href="http://snipplr.com/view/12207/htmlspecialchars/">View ASP implementation on Snipplr</a></p>Scotthttp://www.blogger.com/profile/00069741645360718046noreply@blogger.com0