{"id":171,"date":"2005-08-19T00:50:14","date_gmt":"2005-08-18T23:50:14","guid":{"rendered":"http:\/\/pgregg.com\/wp\/?p=171"},"modified":"2005-08-19T00:50:14","modified_gmt":"2005-08-18T23:50:14","slug":"string-case-conversion-in-php","status":"publish","type":"post","link":"https:\/\/blog.pgregg.com\/blog\/2005\/08\/string-case-conversion-in-php\/","title":{"rendered":"String Case Conversion in PHP"},"content":{"rendered":"<p>Occasionally I read through some comments on the <a href=\"http:\/\/www.php.net\/manual\/en\/index.php\" rel=\"nofollow\" target=\"_blank\">PHP Manual<\/a>, sometimes to get ideas on different methods of doing things, other times just to try to keep current with some of the vast array of functions available.<\/p>\n<p>Sometimes, I see things that really scare me &#8211; code that is written and published with the best will in the world from the author &#8211; but yet displays a lack of a deeper understanding of how to solve a problem.\u00a0 One such case was the <a href=\"http:\/\/uk.php.net\/manual\/en\/function.str-shuffle.php#54381\" rel=\"nofollow\" target=\"_blank\">invert_case() and rand_case()<\/a> functions which basically looped through each character in a string doing whatever it had to do to each character as it went.\u00a0 Highly inefficient.<\/p>\n<p>Remember, the only difference in ASCII between an uppercase letter and a lowercase letter is a single bit that is 0 for uppercase and 1 for lowercase.<\/p>\n<p>This brief tutorial is based on code available at:<br \/>\n<a href=\"http:\/\/www.pgregg.com\/projects\/php\/code\/str_case.phps\" rel=\"nofollow\" target=\"_blank\">http:\/\/www.pgregg.com\/projects\/php\/code\/str_case.phps<\/a><br \/>\nand you can see example output at:<br \/>\n<a href=\"http:\/\/www.pgregg.com\/projects\/php\/code\/str_case.php\" rel=\"nofollow\" target=\"_blank\">http:\/\/www.pgregg.com\/projects\/php\/code\/str_case.php<\/a><\/p>\n<p>Surely it would be possible to write some code that would simply flip this bit in each character to the value you want:<br \/>\n&#8211; AND with 0 to force uppercase<br \/>\n&#8211; OR with 1 to force lowercase<br \/>\n&#8211; XOR with 1 to invert the case<br \/>\n&#8211; randomly set it to 1 or 0 to set random case.<\/p>\n<p>There are two methods to achieving this, the first makes a simple character mask and performs a bitwise operation on the string as a whole to change it as required.\u00a0 This method is designed to help teach how this works.\u00a0 The second method uses the power of the PCRE engine by using a regex to calculate the changes and apply them in one simple step.<\/p>\n<p>Both solutions are, I believe, elegant and are presented here for you.<\/p>\n<p>Solution #1:<\/p>\n<table style=\"width: 95%;\" cellspacing=\"4\" cellpadding=\"6\" align=\"center\">\n<tbody>\n<tr>\n<td class=\"punquote\"><span class=\"puntext\"><strong>Code:<\/strong><\/span><\/p>\n<pre>\/\/ Code that will invert the case of every character in $input\n    \/\/ The solution is to flip the value of 3rd bit in each character\n    \/\/ if the character is a letter. This is done with XOR against a space (hex 32)\n    $stringmask = preg_replace(\"\/[^a-z]\/i\", chr(0), $input); \/\/ replace nonstrings with NULL\n    $stringmask = preg_replace(\"\/[a-z]\/i\", ' ', $stringmask); \/\/ replace strings with space\n    return $input ^ $stringmask;<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span class=\"puntext\"><br \/>\nThe method here is to generate a string mask, in two stages, that will act as a bitmask to XOR the 3rd bit of every letter in the string.\u00a0 Stage 1 is to replace all non-letters will a NULL byte (all zeros) and Stage 2 is to replace all letters with a space (ASCII 32) which just happens to be a byte with just the 3rd bit set to 1 i.e. 00100000<br \/>\nAll we have to do then is XOR our input with the string mask and magically the case of all letters in the entire string are flipped.<\/span><\/p>\n<p>Solution #2:<\/p>\n<p>&nbsp;<\/p>\n<table style=\"width: 95%;\" cellspacing=\"4\" cellpadding=\"6\" align=\"center\">\n<tbody>\n<tr>\n<td class=\"punquote\"><span class=\"puntext\"><strong>Code:<\/strong><\/span><\/p>\n<pre>return preg_replace('\/[a-z]+\/ie', ''$0' ^ str_pad('', strlen('$0'), ' ')', $input);<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span class=\"puntext\"><br \/>\nMuch more compact and works by using a regex looking for letters and using the i (case insensitive) modifier and most importantly the e (evaluate) modifier so we can replace by executing php code.\u00a0 In this case, we look for batches of letters and replace them with itself XORed with a string of spaces (of the same length).<\/span><\/p>\n<p>Similar principles apply to the random case example, but we complicate this slightly by adding and invert mask (to the solution 1 method). This invert mask is created by taking a random amount of spaces (between 0 and the size of the input string). We then pad this out to the size of the original string with NULL bytes and finally randomise the order with str_shuffle().\u00a0 We then bitwise AND the stringmask and the invertmask so we create a new mask where randomly letters in the mask have spaces or NULLs.\u00a0 We then XOR this to the original string as before and before you know it you have a randomly capitalised string.<br \/>\nThe Solution 2 version requires you to remove the + so that we only match a single letter at a time (or else our randomly chosen case would apply to words at a time), and we use a termary to randomly decide on using a space or a NULL:<\/p>\n<p>&nbsp;<\/p>\n<table style=\"width: 95%;\" cellspacing=\"4\" cellpadding=\"6\" align=\"center\">\n<tbody>\n<tr>\n<td class=\"punquote\"><span class=\"puntext\"><strong>Code:<\/strong><\/span><\/p>\n<pre>return preg_replace('\/[a-z]\/ie', '(rand(0,1) ? '$0' ^ ' ' : '$0')', $input);<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span class=\"puntext\"><br \/>\nI hope this has been a worthwhile read and I would certainly welcome feedback on this article.<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Occasionally I read through some comments on the PHP Manual, sometimes to get ideas on different methods of doing things, other times just to try to keep current with some of the vast array of functions available. Sometimes, I see things that really scare me &#8211; code that is written and published with the best &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/blog.pgregg.com\/blog\/2005\/08\/string-case-conversion-in-php\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;String Case Conversion in PHP&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[10],"tags":[81,93],"class_list":["post-171","post","type-post","status-publish","format-standard","hentry","category-php","tag-php-2","tag-software-2"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pbQOUu-2L","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/posts\/171","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/comments?post=171"}],"version-history":[{"count":0,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/posts\/171\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/media?parent=171"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/categories?post=171"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/tags?post=171"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}