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