Erottelija.java |
1 package fi.jyu.mit.ohj2; 2 import java.util.Enumeration; 3 4 /** 5 * Luokka StringTokenizerin korvaajaksi. Erona 6 * on se että jonon loppuessa ei tule ongelmia ja 7 * peräkkäisten erottimien välistä tulee tyhjä jono. 8 * <pre> 9 * Esimerkki: 10 * public static void main(String[] args) { 11 * Erottelija erottaja = new Erottelija("12;3.5:kissa,,,istuu puussa,3.4", 12 * ";:,"); 13 * System.out.println("Palasia: " + erottaja.countTokens()); 14 * for (int i=1; erottaja.hasMoreTokens(); i++ ) 15 * System.out.println(i + ": |" + erottaja.nextToken()+"|"); 16 * System.err.println("8: |"+erottaja.nextToken()+"|"); 17 * erottaja.reset(); 18 * System.out.println(erottaja.nextToken(0)); 19 * System.out.println(erottaja.countRemaininTokens()); 20 * System.out.println(erottaja.rest()); 21 * System.out.println(erottaja.nextToken(0.0)); 22 * System.out.println(erottaja.nextToken(2)); 23 * System.out.println(erottaja.nextToken(2.1)); 24 * System.out.println(erottaja.countRemainingTokens()); 25 * System.out.println(erottaja.rest()); 26 * } 27 * 28 * Tulostaa: 29 * 30 * Palasia: 7 31 * 1: |12| 32 * 2: |3.5| 33 * 3: |kissa| 34 * 4: || 35 * 5: || 36 * 6: |istuu puussa| 37 * 7: |3.4| 38 * 8: || 39 * 12 40 * 6 41 * 3.5:kissa,,,istuu puussa,3.4 42 * 3 43 * ,istuu puussa,3.4 44 * 12 45 * 3.5 46 * 2 47 * 2.1 48 * </pre> 49 * @author vesal 50 * @version 11.3.2007 51 * 52 * @example 53 * <pre name="testErottelija"> 54 * Erottelija erottaja = new Erottelija("12;3.5:kissa,,,istuu puussa,3.4", 55 * ";:,"); 56 * erottaja.nextToken() === $s; erottaja.hasMoreTokens() === $tokens; 57 * erottaja.countRemainingTokens() === $n; erottaja.rest() === $rest; 58 * 59 * $i | $s | $tokens | $n | $rest 60 * -------------------------------------------------------------------------- 61 * 0 | --- | true | 7 | "12;3.5:kissa,,,istuu puussa,3.4" 62 * 1 | "12" | true | 6 | "3.5:kissa,,,istuu puussa,3.4" 63 * 2 | "3.5" | true | 5 | "kissa,,,istuu puussa,3.4" 64 * 3 | "kissa" | true | 4 | ",,istuu puussa,3.4" 65 * 4 | "" | true | 3 | ",istuu puussa,3.4" 66 * 5 | "" | true | 2 | "istuu puussa,3.4" 67 * 6 | "istuu puussa" | true | 1 | "3.4" 68 * 7 | "3.4" | false | 0 | "" 69 * 8 | "" | false | 0 | "" 70 * 9 | "" | false | 0 | "" 71 * 72 * erottaja.nextToken(";","kissa") === "kissa"; 73 * 74 * @example 75 * </pre> 76 * <pre name="testErottelijaEnd"> 77 * Erottelija erottaja = new Erottelija("12;3.5:kissa,,,istuu puussa,3.4;;", 78 * ";:,"); 79 * erottaja.nextToken() === $s; erottaja.hasMoreTokens() === $tokens; 80 * erottaja.countRemainingTokens() === $n; erottaja.rest() === $rest; 81 * 82 * $i | $s | $tokens | $n | $rest 83 * -------------------------------------------------------------------------- 84 * 0 | --- | true | 9 | "12;3.5:kissa,,,istuu puussa,3.4;;" 85 * 1 | "12" | true | 8 | "3.5:kissa,,,istuu puussa,3.4;;" 86 * 2 | "3.5" | true | 7 | "kissa,,,istuu puussa,3.4;;" 87 * 3 | "kissa" | true | 6 | ",,istuu puussa,3.4;;" 88 * 4 | "" | true | 5 | ",istuu puussa,3.4;;" 89 * 5 | "" | true | 4 | "istuu puussa,3.4;;" 90 * 6 | "istuu puussa" | true | 3 | "3.4;;" 91 * 7 | "3.4" | true | 2 | ";" 92 * 8 | "" | true | 1 | "" 93 * 9 | "" | false | 0 | "" 94 * 10 | "" | false | 0 | "" 95 * 96 * erottaja.nextToken(";","kissa") === "kissa"; 97 * </pre> 98 */ 99 @SuppressWarnings("unchecked") 100 public class Erottelija implements Enumeration { // NOPMD - enum ok 101 102 /** 103 * Etsitään mistä kohti jonosta str löytyy ensimmäinen erotinmerkki 104 * joukosta delim. Etsintä aloitetaan paikasta pos. 105 * @param str mistä jonosta etsitään 106 * @param delim joukko erotinmerkkejä 107 * @param pos paikka josta aloitetaan 108 * @return palauttaa ensimmäisen esiintymän tai -1 jos ei löydy 109 * @example 110 * <pre name="test"> 111 * indexOfAny("a;, b",",; ",0) === 1 112 * indexOfAny("a;, b",",; ",2) === 2 113 * indexOfAny("a;, b"," ",0) === 3 114 * indexOfAny("a;, b",".",0) === -1 115 * indexOfAny(null,",; ",0) === -1 116 * indexOfAny("a b",",; ",-1) === 1 117 * </pre> 118 */ 119 public static int indexOfAny(String str, String delim, int pos) { 120 int i=pos; if ( i<0 ) i = 0; 121 if ( str == null || delim == null ) return -1; 122 for ( ; i<str.length(); i++ ) { 123 char c = str.charAt(i); 124 if ( delim.indexOf(c) >= 0 ) return i; 125 } 126 return -1; 127 } 128 129 /** 130 * Etsitään mistä kohti jonosta str löytyy ensimmäinen erotinmerkki 131 * joukosta delim. Etsintä aloitetaan alusta. 132 * @param str mistä jonosta etsitään 133 * @param delim joukko erotinmerkkejä 134 * @return palauttaa ensimmäisen esiintymän tai -1 jos ei löydy 135 * @example 136 * <pre name="test"> 137 * indexOfAny("a;, b",",; ") === 1 138 * </pre> 139 */ 140 public static int indexOfAny(String str, String delim) { 141 return indexOfAny(str,delim,0); 142 } 143 144 145 private String str; 146 private final String delim; 147 private int pos=0; 148 149 /** 150 * Luodaan erottelija, joka erottelee jonosta str palasia minkä tahansa 151 * joukosta delim löytyvän merkin kohdalta. 152 * @param str jono josta erotellaan 153 * @param delim erottavien merkkien joukko 154 */ 155 public Erottelija(String str, String delim) { 156 this.str = str; 157 this.delim = delim; 158 } 159 160 /** 161 * Luodaan erottelija, joka erottelee jonosta str palasia välilyönnin 162 * kohdalta. 163 * @param str jono josta erotellaan 164 * @example 165 * <pre name="test"> 166 * //01234 167 * Erottelija erottaja = new Erottelija("a b "); 168 * erottaja.countTokens() === 3; 169 * </pre> 170 */ 171 public Erottelija(String str) { 172 this.str = str; 173 this.delim = " "; 174 } 175 176 /** 177 * Palauttaa seuraavan palasen jonosta 178 * @return jonon seuraava palanen 179 * @example 180 * <pre name="test"> 181 * Erottelija erottaja = new Erottelija("a;b;",";"); 182 * erottaja.nextToken() === $s; erottaja.hasMoreTokens() === $tokens; 183 * erottaja.countRemainingTokens() === $n; erottaja.rest() === $rest; 184 * 185 * $i | $s | $tokens | $n | $rest 186 * -------------------------------------------------------------------------- 187 * 0 | --- | true | 3 | "a;b;" 188 * 1 | "a" | true | 2 | "b;" 189 * 2 | "b" | true | 1 | "" 190 * 3 | "" | false | 0 | "" 191 * 4 | "" | false | 0 | "" 192 * </pre> 193 */ 194 public String nextToken() { 195 return nextToken(delim); 196 } 197 198 /** 199 * Tarkistaa onko erotinmerkkiä juuri paikan vasemmalla puolella 200 * @param pos paikka josta tutkitaan 201 * @param delim kelpaavat erotinmerkit 202 * @return true jos on erotin merkki vasemmalla puolella, false muuten 203 * @example 204 * <pre name="test"> 205 * //01234 206 * Erottelija erottaja = new Erottelija("a;b;",";"); 207 * erottaja.isDelimBefore(0,";") === false; 208 * erottaja.isDelimBefore(1,";") === false; 209 * erottaja.isDelimBefore(2,";") === true; 210 * erottaja.isDelimBefore(3,";") === false; 211 * erottaja.isDelimBefore(4,";") === true; 212 * erottaja.isDelimBefore(5,";") === false; 213 * </pre> 214 */ 215 public boolean isDelimBefore(int pos, String delim) { 216 if ( pos <= 0 ) return false; 217 if ( pos > str.length() ) return false; 218 String usedDelim = delim; 219 if ( delim == null ) usedDelim = this.delim; 220 char c = str.charAt(pos-1); 221 return ( usedDelim.indexOf(c) >= 0 ); 222 } 223 224 /** 225 * Tarkistaa onko erotinmerkkiä juuri paikan vasemmalla puolella 226 * @param pos paikka josta tutkitaan 227 * @return true jos on erotin merkki vasemmalla puolella, false muuten 228 * @example 229 * <pre name="test"> 230 * //01234 231 * Erottelija erottaja = new Erottelija("a;b;",";"); 232 * erottaja.isDelimBefore(0) === false; 233 * erottaja.isDelimBefore(1) === false; 234 * erottaja.isDelimBefore(2) === true; 235 * erottaja.isDelimBefore(3) === false; 236 * erottaja.isDelimBefore(4) === true; 237 * erottaja.isDelimBefore(5) === false; 238 * </pre> 239 */ 240 public boolean isDelimBefore(int pos) { 241 return isDelimBefore(pos,null); 242 } 243 244 /** 245 * Tarkistaa onko erotinmerkkiä juuri nykypaikan vasemmalla puolella 246 * @return true jos on erotin merkki vasemmalla puolella, false muuten 247 * @example 248 * <pre name="test"> 249 * //01234 250 * Erottelija erottaja = new Erottelija("a;b;",";"); 251 * erottaja.isDelimBefore() === false; 252 * erottaja.nextToken() === "a"; erottaja.isDelimBefore() === true; 253 * erottaja.nextToken() === "b"; erottaja.isDelimBefore() === true; 254 * erottaja.nextToken() === ""; erottaja.isDelimBefore() === false; 255 * erottaja.nextToken() === ""; erottaja.isDelimBefore() === false; 256 * </pre> 257 */ 258 public boolean isDelimBefore() { 259 return isDelimBefore(pos,null); 260 } 261 262 263 /** 264 * Palauttaa seuraavan palasen jonosta. 265 * @param delim erotinjoukko, jonka perusteella perusteella erotetaan 266 * @return jonon seuraava palanen 267 * @example 268 * <pre name="test"> 269 * Erottelija erottaja = new Erottelija("a b;c"); 270 * erottaja.nextToken(" ") === "a"; 271 * erottaja.nextToken(" ") === "b;c"; 272 * erottaja = new Erottelija("a b;c"); 273 * erottaja.nextToken(" ") === "a"; 274 * erottaja.nextToken(";") === "b"; 275 * erottaja.nextToken(" ") === "c"; 276 * erottaja.nextToken(" ") === ""; 277 * erottaja = new Erottelija(null); 278 * erottaja.nextToken(" ") === ""; 279 * erottaja = new Erottelija("a b"); 280 * erottaja.nextToken(null) === "a"; 281 * </pre> 282 */ 283 public String nextToken(String delim) { 284 if ( str == null ) return ""; 285 int len = str.length(); 286 if ( pos > len ) return ""; 287 if ( pos == len ) { pos = len+1; return ""; } 288 String usedDelim = delim; 289 if ( delim == null ) usedDelim = this.delim; 290 int nextpos = indexOfAny(str,usedDelim,pos); 291 if ( nextpos < 0 ) nextpos = len; 292 String result = str.substring(pos,nextpos); 293 pos = nextpos; 294 if ( pos < len ) pos++; 295 return result; 296 } 297 298 /** 299 * Ottaa seuraavan palasen ja jos se on tyhjä, niin palauttaa def-jonon. 300 * @param delim erotinjoukko, jonka perusteella perusteella erotetaan 301 * @param def oletusarvo jos seuraava palanen on tyhjä 302 * @return jonon seuraava palanen tai oletus 303 * @example 304 * <pre name="test"> 305 * Erottelija erottaja = new Erottelija("a b;c"); 306 * erottaja.nextToken(" ","d") === "a"; 307 * erottaja.nextToken(" ","d") === "b;c"; 308 * erottaja.nextToken(" ","d") === "d"; 309 * </pre> 310 */ 311 public String nextToken(String delim, String def) { 312 String piece = nextToken(delim); 313 if ( piece.length() > 0 ) return piece; 314 return def; 315 } 316 317 /** 318 * Palauttaa jonosta seuraavan kokonaisluvun ja oletuksen jos luku ei ole 319 * kunnollinen. 320 * @param delim erotinjoukko, jonka perusteella perusteella erotetaan 321 * @param def oletusarvo jos luku ei ole kunnollinen 322 * @return seuraava kokonaisluku tai oletus 323 * @example 324 * <pre name="test"> 325 * Erottelija erottaja = new Erottelija("1;2"); 326 * erottaja.nextToken(";",3) === 1; 327 * erottaja.nextToken(";",3) === 2; 328 * erottaja.nextToken(";",3) === 3; 329 * </pre> 330 */ 331 public int nextToken(String delim, int def) { 332 String piece = nextToken(delim); 333 return Mjonot.erotaInt(piece,def); 334 } 335 336 /** 337 * Palauttaa jonosta seuraavan kokonaisluvun ja oletuksen jos luku ei ole 338 * kunnollinen. 339 * @param def oletusarvo jos luku ei ole kunnollinen 340 * @return seuraava kokonaisluku tai oletus 341 * @example 342 * <pre name="test"> 343 * Erottelija erottaja = new Erottelija("1 2"); 344 * erottaja.nextToken(3) === 1; 345 * erottaja.nextToken(3) === 2; 346 * erottaja.nextToken(3) === 3; 347 * </pre> 348 */ 349 public int nextToken(int def) { 350 return nextToken(null,def); 351 } 352 353 354 /** 355 * Palauttaa jonosta seuraavan kokonaisluvun ja 0 jos luku ei ole 356 * kunnollinen. 357 * @return seuraava kokonaisluku tai 0 358 * @example 359 * <pre name="test"> 360 * Erottelija erottaja = new Erottelija("1 2"); 361 * erottaja.nextInt() === 1; 362 * erottaja.nextInt() === 2; 363 * erottaja.nextInt() === 0; 364 * </pre> 365 */ 366 public int nextInt() { 367 return nextToken(0); 368 } 369 370 371 /** 372 * Palauttaa jonosta seuraavan reaaliluvun ja oletuksen jos luku ei ole 373 * kunnollinen. 374 * @param delim erotinjoukko, jonka perusteella perusteella erotetaan 375 * @param def oletusarvo jos luku ei ole kunnollinen 376 * @return seuraava reaaliluku tai oletus 377 * @example 378 * <pre name="test"> 379 * Erottelija erottaja = new Erottelija("1;2"); 380 * erottaja.nextToken(";",3.1) ~~~ 1.0; 381 * erottaja.nextToken(";",3.1) ~~~ 2.0; 382 * erottaja.nextToken(";",3.1) ~~~ 3.1; 383 * </pre> 384 */ 385 public double nextToken(String delim, double def) { 386 String piece = nextToken(delim); 387 return Mjonot.erotaDouble(piece,def); 388 } 389 390 /** 391 * Palauttaa jonosta seuraavan reaaliluvun ja oletuksen jos luku ei ole 392 * kunnollinen. 393 * @param def oletusarvo jos luku ei ole kunnollinen 394 * @return seuraava reaaliluku tai oletus 395 * @example 396 * <pre name="test"> 397 * Erottelija erottaja = new Erottelija("1 2"); 398 * erottaja.nextToken(3.1) ~~~ 1.0; 399 * erottaja.nextToken(3.1) ~~~ 2.0; 400 * erottaja.nextToken(3.1) ~~~ 3.1; 401 * </pre> 402 */ 403 public double nextToken(double def) { 404 return nextToken(null,def); 405 } 406 407 /** 408 * Palauttaa jonosta seuraavan reaaliluvun ja 0.0 jos luku ei ole 409 * kunnollinen. 410 * @return seuraava reaaliluku tai 0.0 411 * @example 412 * <pre name="test"> 413 * Erottelija erottaja = new Erottelija("1 2"); 414 * erottaja.nextDouble() ~~~ 1.0; 415 * erottaja.nextDouble() ~~~ 2.0; 416 * erottaja.nextDouble() ~~~ 0.0; 417 * </pre> 418 */ 419 public double nextDouble() { 420 return nextToken(0.0); 421 } 422 423 424 /** 425 * Laskee palasten lukumäärän. 426 * @param pos paikka josta laskeminen aloitetaan 427 * @return palasten lukumäärä. 428 */ 429 public int countTokens(int pos) { 430 int n=1; 431 int len=str.length(); 432 if ( pos > len ) return 0; 433 if ( pos == len ) return isDelimBefore(pos) ? 1 : 0; 434 for (int i=pos; i<len; i++) { 435 char c = str.charAt(i); 436 if ( delim.indexOf(c) >= 0 ) n++; 437 } 438 return n; 439 } 440 441 /** 442 * Laskee palasten lukumäärän. 443 * @return palasten lukumäärä. 444 */ 445 public int countTokens() { 446 return countTokens(0); 447 } 448 449 450 /** 451 * Laskee palasten lukumäärän. 452 * @return palasten lukumäärä. 453 */ 454 public int countRemainingTokens() { 455 return countTokens(pos); 456 } 457 458 /** 459 * Tarkistaa että vieläkö palasia on jäljellä. 460 * @return onko palasia jäljellä 461 */ 462 public boolean hasMoreElements() { 463 if ( isDelimBefore() ) return true; 464 return ( pos < str.length() ); 465 } 466 467 /** 468 * Tarkistaa että vieläkö palasia on jäljellä. 469 * @return onko palasia jäljellä 470 */ 471 public boolean hasMoreTokens() { 472 return hasMoreElements(); 473 } 474 475 /** 476 * Palauttaa seuraavan palasen Objectina. 477 * @return seuraava palanen 478 * @example 479 * <pre name="test"> 480 * Erottelija erottaja = new Erottelija("1 2"); 481 * erottaja.nextElement().toString() === "1"; 482 * </pre> 483 */ 484 public Object nextElement() { 485 return nextToken(); 486 } 487 488 /** 489 * Siivoaa palasteltavan jonon turhista välilyönneistä 490 * @example 491 * <pre name="test"> 492 * Erottelija erottaja = new Erottelija(" 1 2 "); 493 * erottaja.countTokens() === 6; 494 * erottaja.trim(); 495 * erottaja.countTokens() === 4; 496 * </pre> 497 */ 498 public void trim() { 499 str = Mjonot.poista_2_tyhjat(str); 500 pos = 0; 501 } 502 503 /** 504 * Palauttaa jäljellä olevan jonon. 505 * @return jäljellä oleva jono. 506 * @example 507 * <pre name="test"> 508 * Erottelija erottaja = new Erottelija(" 1 2 "); 509 * erottaja.trim(); 510 * erottaja.rest() === " 1 2 "; 511 * </pre> 512 */ 513 public String rest() { 514 if ( !hasMoreTokens() ) return ""; 515 return str.substring(pos); 516 } 517 518 /** 519 * Palauttaa paikan erottelijan alkuun. 520 */ 521 public void reset() { 522 pos = 0; 523 } 524 525 /** 526 * Testataan Erottelijaluokkaa 527 * @param args ei käytössä 528 */ 529 /* 530 public static void main(String[] args) { 531 Erottelija erottaja = new Erottelija("12;3.5:kissa,,,istuu puussa,3.4",";:,"); 532 System.out.println("Palasia: " + erottaja.countTokens()); 533 for (int i=1; erottaja.hasMoreTokens(); i++ ) 534 System.out.println(i + ": |" + erottaja.nextToken()+"|"); 535 System.out.println("8: |"+erottaja.nextToken()+"|"); 536 erottaja.reset(); 537 System.out.println(erottaja.nextToken(0)); 538 System.out.println(erottaja.countRemainingTokens()); 539 System.out.println(erottaja.rest()); 540 System.out.println(erottaja.nextToken(0.0)); 541 System.out.println(erottaja.nextToken(2)); 542 System.out.println(erottaja.nextToken(2.1)); 543 System.out.println(erottaja.countRemainingTokens()); 544 System.out.println(erottaja.rest()); 545 } 546 */ 547 } 548