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