1 /******************************************************************************* 2 3 copyright: Copyright (c) 2006 Kris Bell. All rights reserved 4 5 license: BSD style: $(LICENSE) 6 7 version: Dec 2006: Initial release 8 9 author: Kris 10 11 Placeholder for a selection of ASCII utilities. These generally will 12 not work with utf8, and cannot be easily extended to utf16 or utf32 13 14 *******************************************************************************/ 15 16 module tango.text.Ascii; 17 18 version (Win32) 19 { 20 private extern (C) int memicmp (in char *, in char *, uint); 21 private extern (C) int memcmp (in char *, in char *, uint); 22 } 23 24 version (Posix) 25 { 26 private extern (C) int memcmp (in char *, in char *, uint); 27 private extern (C) int strncasecmp (in char *, in char*, uint); 28 private alias strncasecmp memicmp; 29 } 30 31 /****************************************************************************** 32 33 Convert to lowercase in-place. 34 35 ******************************************************************************/ 36 37 char[] toLower (char[] src) 38 { 39 foreach (ref c; src) 40 if (c>= 'A' && c <= 'Z') 41 c = cast(char)(c + 32); 42 return src; 43 } 44 45 /****************************************************************************** 46 47 Convert to lowercase. Returns the converted content in dst. 48 49 ******************************************************************************/ 50 51 char[] toLower (const(char[]) src, char[] dst) 52 { 53 assert (dst.length >= src.length); 54 dst[0 .. src.length] = src [0 .. $]; 55 56 return toLower(dst [0 .. src.length]); 57 } 58 59 /****************************************************************************** 60 61 Convert to uppercase in-place. 62 63 ******************************************************************************/ 64 65 char[] toUpper (char[] src) 66 { 67 foreach (ref c; src) 68 if (c>= 'a' && c <= 'z') 69 c = cast(char)(c - 32); 70 return src; 71 } 72 73 /****************************************************************************** 74 75 Convert to uppercase. Returns the converted content in dst. 76 77 ******************************************************************************/ 78 79 char[] toUpper (const(char[]) src, char[] dst) 80 { 81 assert (dst.length >= src.length); 82 dst[0 .. src.length] = src [0 .. $]; 83 84 return toUpper(dst [0 .. src.length]); 85 } 86 87 /****************************************************************************** 88 89 Compare two char[] ignoring case. Returns 0 if equal 90 91 ******************************************************************************/ 92 93 int icompare (const(char[]) s1, const(char[]) s2) 94 { 95 auto len = s1.length; 96 if (s2.length < len) 97 len = s2.length; 98 99 auto result = memicmp (s1.ptr, s2.ptr, cast(int)len); 100 101 if (result is 0) 102 result = cast(int)s1.length - cast(int)s2.length; 103 return result; 104 } 105 106 107 /****************************************************************************** 108 109 Compare two char[] with case. Returns 0 if equal 110 111 ******************************************************************************/ 112 113 int compare (const(char[]) s1, const(char[]) s2) 114 { 115 auto len = s1.length; 116 if (s2.length < len) 117 len = s2.length; 118 119 auto result = memcmp (s1.ptr, s2.ptr, cast(int)len); 120 121 if (result is 0) 122 result = cast(int)s1.length - cast(int)s2.length; 123 return result; 124 } 125 126 127 128 /****************************************************************************** 129 130 Return the index position of a text pattern within src, or 131 src.length upon failure. 132 133 This is a case-insensitive search (with thanks to Nietsnie) 134 135 ******************************************************************************/ 136 137 size_t isearch (in char[] src, in char[] pattern) 138 { 139 __gshared immutable char[] _caseMap = 140 [ 141 '\000','\001','\002','\003','\004','\005','\006','\007', 142 '\010','\011','\012','\013','\014','\015','\016','\017', 143 '\020','\021','\022','\023','\024','\025','\026','\027', 144 '\030','\031','\032','\033','\034','\035','\036','\037', 145 '\040','\041','\042','\043','\044','\045','\046','\047', 146 '\050','\051','\052','\053','\054','\055','\056','\057', 147 '\060','\061','\062','\063','\064','\065','\066','\067', 148 '\070','\071','\072','\073','\074','\075','\076','\077', 149 '\100','\141','\142','\143','\144','\145','\146','\147', 150 '\150','\151','\152','\153','\154','\155','\156','\157', 151 '\160','\161','\162','\163','\164','\165','\166','\167', 152 '\170','\171','\172','\133','\134','\135','\136','\137', 153 '\140','\141','\142','\143','\144','\145','\146','\147', 154 '\150','\151','\152','\153','\154','\155','\156','\157', 155 '\160','\161','\162','\163','\164','\165','\166','\167', 156 '\170','\171','\172','\173','\174','\175','\176','\177', 157 '\200','\201','\202','\203','\204','\205','\206','\207', 158 '\210','\211','\212','\213','\214','\215','\216','\217', 159 '\220','\221','\222','\223','\224','\225','\226','\227', 160 '\230','\231','\232','\233','\234','\235','\236','\237', 161 '\240','\241','\242','\243','\244','\245','\246','\247', 162 '\250','\251','\252','\253','\254','\255','\256','\257', 163 '\260','\261','\262','\263','\264','\265','\266','\267', 164 '\270','\271','\272','\273','\274','\275','\276','\277', 165 '\300','\341','\342','\343','\344','\345','\346','\347', 166 '\350','\351','\352','\353','\354','\355','\356','\357', 167 '\360','\361','\362','\363','\364','\365','\366','\367', 168 '\370','\371','\372','\333','\334','\335','\336','\337', 169 '\340','\341','\342','\343','\344','\345','\346','\347', 170 '\350','\351','\352','\353','\354','\355','\356','\357', 171 '\360','\361','\362','\363','\364','\365','\366','\367', 172 '\370','\371','\372','\373','\374','\375','\376','\377', 173 ]; 174 175 176 assert(src.ptr); 177 assert(pattern.ptr); 178 179 for (int i1=0, i2; i1 <= cast(int)(src.length - pattern.length); ++i1) 180 { 181 for (i2=0; i2 < pattern.length; ++i2) 182 if (_caseMap[src[i1 + i2]] != _caseMap[pattern[i2]]) 183 break; 184 185 if (i2 is pattern.length) 186 return i1; 187 } 188 return src.length; 189 } 190 191 192 193 /****************************************************************************** 194 195 ******************************************************************************/ 196 197 debug (UnitTest) 198 { 199 unittest 200 { 201 char[20] tmp; 202 203 assert (toLower("1bac", tmp) == "1bac"); 204 assert (toLower("1BAC", tmp) == "1bac"); 205 assert (toUpper("1bac", tmp) == "1BAC"); 206 assert (toUpper("1BAC", tmp) == "1BAC"); 207 assert (icompare ("ABC", "abc") is 0); 208 assert (icompare ("abc", "abc") is 0); 209 assert (icompare ("abcd", "abc") > 0); 210 assert (icompare ("abc", "abcd") < 0); 211 assert (icompare ("ACC", "abc") > 0); 212 213 assert (isearch ("ACC", "abc") is 3); 214 assert (isearch ("ACC", "acc") is 0); 215 assert (isearch ("aACC", "acc") is 1); 216 } 217 } 218 219 debug (Ascii) 220 { 221 void main() {} 222 }