001package com.hfg.util; 002 003import java.io.IOException; 004import java.io.OutputStream; 005 006//------------------------------------------------------------------------------ 007/** 008 * A StringBuilder with extra functionality [delimtedAppend(), printf(), appendln(), 009 * replaceAll(), and carriage return support]. 010 * 011 * @author J. Alex Taylor, hairyfatguy.com 012 */ 013//------------------------------------------------------------------------------ 014// com.hfg XML/HTML Coding Library 015// 016// This library is free software; you can redistribute it and/or 017// modify it under the terms of the GNU Lesser General Public 018// License as published by the Free Software Foundation; either 019// version 2.1 of the License, or (at your option) any later version. 020// 021// This library is distributed in the hope that it will be useful, 022// but WITHOUT ANY WARRANTY; without even the implied warranty of 023// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 024// Lesser General Public License for more details. 025// 026// You should have received a copy of the GNU Lesser General Public 027// License along with this library; if not, write to the Free Software 028// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 029// 030// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 031// jataylor@hairyfatguy.com 032//------------------------------------------------------------------------------ 033 034// Can't extend StringBuilder since it is is a final class so we just have to wrap it. 035public class StringBuilderPlus extends OutputStream implements CharSequence 036{ 037 private StringBuilder mBuffer; 038 private String mDelimiter = sDefaultDelimiter; 039 private String mLineSeparator = sDefaultLineSeparator; 040 private boolean mCarriageReturnEnabled; 041 042 private static String sDefaultDelimiter = ", "; 043 private static String sDefaultLineSeparator = System.getProperty("line.separator"); 044 045 //########################################################################## 046 // CONSTRUCTORS 047 //########################################################################## 048 049 //-------------------------------------------------------------------------- 050 public StringBuilderPlus() 051 { 052 mBuffer = new StringBuilder(); 053 } 054 055 //-------------------------------------------------------------------------- 056 public StringBuilderPlus(int inSize) 057 { 058 mBuffer = new StringBuilder(inSize); 059 } 060 061 //-------------------------------------------------------------------------- 062 public StringBuilderPlus(CharSequence inContent) 063 { 064 mBuffer = new StringBuilder(); 065 if (inContent != null) 066 { 067 mBuffer.append(inContent); 068 } 069 } 070 071 //########################################################################## 072 // PUBLIC METHODS 073 //########################################################################## 074 075 //-------------------------------------------------------------------------- 076 /** 077 Sets an override for the default line separator of System.getProperty("line.separator"). 078 */ 079 public static void setDefaultLineSeparator(String inValue) 080 { 081 sDefaultLineSeparator = inValue; 082 } 083 084 //-------------------------------------------------------------------------- 085 public static void setDefaultDelimiter(String inValue) 086 { 087 sDefaultDelimiter = inValue; 088 } 089 090 091 //-------------------------------------------------------------------------- 092 public StringBuilderPlus setLineSeparator(String inValue) 093 { 094 mLineSeparator = inValue; 095 096 return this; 097 } 098 099 //-------------------------------------------------------------------------- 100 public StringBuilderPlus setDelimiter(String inValue) 101 { 102 mDelimiter = inValue; 103 104 return this; 105 } 106 107 //-------------------------------------------------------------------------- 108 public String getDelimiter() 109 { 110 return mDelimiter; 111 } 112 113 //-------------------------------------------------------------------------- 114 public void moveCharAt(int inFromIndex, int intToIndex) 115 { 116 char charToMove = mBuffer.charAt(inFromIndex); 117 mBuffer.insert(inFromIndex < intToIndex ? intToIndex + 1 : intToIndex, charToMove); 118 mBuffer.deleteCharAt(inFromIndex < intToIndex ? inFromIndex : inFromIndex + 1); 119 } 120 121 //-------------------------------------------------------------------------- 122 public StringBuilderPlus replaceAll(Character inTarget, Character inReplacement) 123 { 124 return replaceAll(inTarget + "", inReplacement != null ? inReplacement + "" : null); 125 } 126 127 //-------------------------------------------------------------------------- 128 public StringBuilderPlus replaceAll(CharSequence inTarget, Character inReplacement) 129 { 130 return replaceAll(inTarget, inReplacement != null ? inReplacement + "" : null); 131 } 132 133 //-------------------------------------------------------------------------- 134 public StringBuilderPlus replaceAll(Character inTarget, CharSequence inReplacement) 135 { 136 return replaceAll(inTarget + "", inReplacement); 137 } 138 139 //-------------------------------------------------------------------------- 140 public StringBuilderPlus replaceAll(CharSequence inTarget, CharSequence inReplacement) 141 { 142 String replacement = inReplacement != null ? inReplacement + "" : ""; 143 144 int index; 145 int fromIndex = 0; 146 while ((index = indexOf(inTarget + "", fromIndex)) >= 0) 147 { 148 replace(index, index + inTarget.length(), replacement); 149 fromIndex = index + replacement.length(); 150 } 151 152 return this; 153 } 154 155 //-------------------------------------------------------------------------- 156 /** 157 Causes any '\r' characters to be immediately interpreted as carriage returns. 158 * @return this StringBuilderPlus object to allow method chaining. 159 */ 160 public StringBuilderPlus enableCarriageReturnSupport() 161 { 162 mCarriageReturnEnabled = true; 163 164 // Process any pre-existing carriage returns 165 if (length() > 0 166 && indexOf("\r") >= 0) 167 { 168 processAddedContentForCarriageReturns(toString()); 169 } 170 171 return this; 172 } 173 174 //-------------------------------------------------------------------------- 175 public StringBuilderPlus disableCarriageReturnSupport() 176 { 177 mCarriageReturnEnabled = false; 178 return this; 179 } 180 181 //-------------------------------------------------------------------------- 182 public boolean startsWith(String inValue) 183 { 184 return toString().startsWith(inValue); 185 } 186 187 //-------------------------------------------------------------------------- 188 public boolean endsWith(String inValue) 189 { 190 return toString().endsWith(inValue); 191 } 192 193 // OutputStream methods 194 195 //-------------------------------------------------------------------------- 196 @Override 197 public void write(int inByte) 198 throws IOException 199 { 200 append((char) inByte); 201 } 202 203 //-------------------------------------------------------------------------- 204 @Override 205 public void write(byte inBytes[], int inOffset, int inLength) 206 { 207 append(new String(inBytes, inOffset, inLength)); 208 } 209 210 //-------------------------------------------------------------------------- 211 @Override 212 public void write(byte inBytes[]) 213 { 214 append(new String(inBytes)); 215 } 216 217 218 219 //-------------------------------------------------------------------------- 220 public StringBuilderPlus delimitedAppend(CharSequence inContent) 221 { 222 delimitIfNecessary(); 223 224 append(inContent); 225 226 return this; 227 } 228 229 //-------------------------------------------------------------------------- 230 public StringBuilderPlus delimitedAppend(char inContent) 231 { 232 delimitIfNecessary(); 233 234 append(inContent); 235 236 return this; 237 } 238 239 //-------------------------------------------------------------------------- 240 public StringBuilderPlus delimitedAppend(int inContent) 241 { 242 delimitIfNecessary(); 243 244 append(inContent); 245 246 return this; 247 } 248 249 //-------------------------------------------------------------------------- 250 public StringBuilderPlus delimitedAppend(long inContent) 251 { 252 delimitIfNecessary(); 253 254 append(inContent); 255 256 return this; 257 } 258 259 //-------------------------------------------------------------------------- 260 public StringBuilderPlus delimitedAppend(float inContent) 261 { 262 delimitIfNecessary(); 263 264 append(inContent); 265 266 return this; 267 } 268 269 //-------------------------------------------------------------------------- 270 public StringBuilderPlus delimitedAppend(double inContent) 271 { 272 delimitIfNecessary(); 273 274 append(inContent); 275 276 return this; 277 } 278 279 //-------------------------------------------------------------------------- 280 public StringBuilderPlus delimitedAppend(Object inContent) 281 { 282 delimitIfNecessary(); 283 284 append(inContent); 285 286 return this; 287 } 288 289 //-------------------------------------------------------------------------- 290 public StringBuilderPlus printf(String inFormatString, Object... inArgs) 291 { 292 return append(String.format(inFormatString, inArgs)); 293 } 294 295 //-------------------------------------------------------------------------- 296 public StringBuilderPlus appendln(CharSequence inContent) 297 { 298 append(inContent); 299 mBuffer.append(mLineSeparator); 300 return this; 301 } 302 303 //-------------------------------------------------------------------------- 304 public StringBuilderPlus appendln() 305 { 306 mBuffer.append(mLineSeparator); 307 308 return this; 309 } 310 311 // Methods from StringBuilder: 312 313 //-------------------------------------------------------------------------- 314 public StringBuilderPlus append(Object inObj) 315 { 316 mBuffer.append(inObj); 317 318 return this; 319 } 320 321 //-------------------------------------------------------------------------- 322 public StringBuilderPlus append(CharSequence inContent) 323 { 324 CharSequence content = inContent; 325 if (mCarriageReturnEnabled 326 && inContent != null 327 && inContent.toString().contains("\r")) 328 { 329 content = processAddedContentForCarriageReturns(inContent); 330 if (content.charAt(0) == '\r') 331 { 332 int lastLineFeedIndex = lastIndexOf("\n"); 333 replace(lastLineFeedIndex + 1, length(), ""); 334 // Remove the '\r' from the beginning of the added content 335 content = content.subSequence(1, content.length()); 336 } 337 } 338 339 mBuffer.append(content); 340 341 return this; 342 } 343 344 //-------------------------------------------------------------------------- 345 public StringBuilderPlus append(CharSequence inContent, int inStart, int inEnd) 346 { 347 mBuffer.append(inContent, inStart, inEnd); 348 349 return this; 350 } 351 352 //-------------------------------------------------------------------------- 353 public StringBuilderPlus append(char[] inContent) 354 { 355 mBuffer.append(inContent); 356 357 return this; 358 } 359 360 //-------------------------------------------------------------------------- 361 public StringBuilderPlus append(char[] inContent, int inOffset, int inLen) 362 { 363 mBuffer.append(inContent, inOffset, inLen); 364 365 return this; 366 } 367 368 //-------------------------------------------------------------------------- 369 public StringBuilderPlus append(boolean inContent) 370 { 371 mBuffer.append(inContent); 372 373 return this; 374 } 375 376 //-------------------------------------------------------------------------- 377 public StringBuilderPlus append(char inContent) 378 { 379 if (mCarriageReturnEnabled 380 && inContent == '\r') 381 { 382 append(inContent + ""); 383 } 384 else 385 { 386 mBuffer.append(inContent); 387 } 388 389 return this; 390 } 391 392 //-------------------------------------------------------------------------- 393 public StringBuilderPlus append(int inContent) 394 { 395 mBuffer.append(inContent); 396 397 return this; 398 } 399 400 //-------------------------------------------------------------------------- 401 public StringBuilderPlus append(long inContent) 402 { 403 mBuffer.append(inContent); 404 405 return this; 406 } 407 408 //-------------------------------------------------------------------------- 409 public StringBuilderPlus append(float inContent) 410 { 411 mBuffer.append(inContent); 412 413 return this; 414 } 415 416 //-------------------------------------------------------------------------- 417 public StringBuilderPlus append(double inContent) 418 { 419 mBuffer.append(inContent); 420 421 return this; 422 } 423 424 //-------------------------------------------------------------------------- 425 public StringBuilderPlus appendCodePoint(int inContent) 426 { 427 mBuffer.appendCodePoint(inContent); 428 429 return this; 430 } 431 432 //-------------------------------------------------------------------------- 433 public StringBuilderPlus delete(int inStart, int inEnd) 434 { 435 mBuffer.delete(inStart, inEnd); 436 437 return this; 438 } 439 440 //-------------------------------------------------------------------------- 441 public StringBuilderPlus deleteCharAt(int inIndex) 442 { 443 mBuffer.deleteCharAt(inIndex); 444 445 return this; 446 } 447 448 //-------------------------------------------------------------------------- 449 public StringBuilderPlus replace(int inStart, int inEnd, String inReplacement) 450 { 451 mBuffer.replace(inStart, inEnd, inReplacement); 452 453 return this; 454 } 455 456 //-------------------------------------------------------------------------- 457 public StringBuilderPlus insert(int inIndex, char[] inContent) 458 { 459 mBuffer.insert(inIndex, inContent); 460 461 return this; 462 } 463 464 //-------------------------------------------------------------------------- 465 public StringBuilderPlus insert(int inIndex, char[] inContent, int inOffset, int inLen) 466 { 467 mBuffer.insert(inIndex, inContent, inOffset, inLen); 468 469 return this; 470 } 471 472 //-------------------------------------------------------------------------- 473 public StringBuilderPlus insert(int inIndex, Object inContent) 474 { 475 mBuffer.insert(inIndex, inContent); 476 477 return this; 478 } 479 480 //-------------------------------------------------------------------------- 481 public StringBuilderPlus insert(int inIndex, CharSequence inContent) 482 { 483 mBuffer.insert(inIndex, inContent); 484 485 return this; 486 } 487 488 //-------------------------------------------------------------------------- 489 public StringBuilderPlus insert(int inIndex, CharSequence inContent, int inStart, int inEnd) 490 { 491 mBuffer.insert(inIndex, inContent, inStart, inEnd); 492 493 return this; 494 } 495 496 //-------------------------------------------------------------------------- 497 public StringBuilderPlus insert(int inIndex, boolean inContent) 498 { 499 mBuffer.insert(inIndex, inContent); 500 501 return this; 502 } 503 504 //-------------------------------------------------------------------------- 505 public StringBuilderPlus insert(int inIndex, char inContent) 506 { 507 mBuffer.insert(inIndex, inContent); 508 509 return this; 510 } 511 512 //-------------------------------------------------------------------------- 513 public StringBuilderPlus insert(int inIndex, int inContent) 514 { 515 mBuffer.insert(inIndex, inContent); 516 517 return this; 518 } 519 520 //-------------------------------------------------------------------------- 521 public StringBuilderPlus insert(int inIndex, long inContent) 522 { 523 mBuffer.insert(inIndex, inContent); 524 525 return this; 526 } 527 528 //-------------------------------------------------------------------------- 529 public StringBuilderPlus insert(int inIndex, float inContent) 530 { 531 mBuffer.insert(inIndex, inContent); 532 533 return this; 534 } 535 536 //-------------------------------------------------------------------------- 537 public StringBuilderPlus insert(int inIndex, double inContent) 538 { 539 mBuffer.insert(inIndex, inContent); 540 541 return this; 542 } 543 544 //-------------------------------------------------------------------------- 545 public int indexOf(String inString) 546 { 547 return mBuffer.indexOf(inString); 548 } 549 550 //-------------------------------------------------------------------------- 551 public int indexOf(String inString, int inFromIndex) 552 { 553 return mBuffer.indexOf(inString, inFromIndex); 554 } 555 556 //-------------------------------------------------------------------------- 557 public int lastIndexOf(String inString) 558 { 559 return mBuffer.lastIndexOf(inString); 560 } 561 562 //-------------------------------------------------------------------------- 563 public int lastIndexOf(String inString, int inFromIndex) 564 { 565 return mBuffer.lastIndexOf(inString, inFromIndex); 566 } 567 568 //-------------------------------------------------------------------------- 569 public StringBuilderPlus reverse() 570 { 571 mBuffer.reverse(); 572 573 return this; 574 } 575 576 //-------------------------------------------------------------------------- 577 @Override 578 public String toString() 579 { 580 return mBuffer.toString(); 581 } 582 583 //-------------------------------------------------------------------------- 584 public int length() 585 { 586 return mBuffer.length(); 587 } 588 589 //-------------------------------------------------------------------------- 590 public int capacity() 591 { 592 return mBuffer.capacity(); 593 } 594 595 //-------------------------------------------------------------------------- 596 public StringBuilderPlus ensureCapacity(int inMinimumCapacity) 597 { 598 mBuffer.ensureCapacity(inMinimumCapacity); 599 600 return this; 601 } 602 603 //-------------------------------------------------------------------------- 604 public StringBuilderPlus trimToSize() 605 { 606 mBuffer.trimToSize(); 607 608 return this; 609 } 610 611 //-------------------------------------------------------------------------- 612 public StringBuilderPlus setLength(int inNewLength) 613 { 614 mBuffer.setLength(inNewLength); 615 616 return this; 617 } 618 619 //-------------------------------------------------------------------------- 620 public char charAt(int inIndex) 621 { 622 return mBuffer.charAt(inIndex); 623 } 624 625 //-------------------------------------------------------------------------- 626 public int codePointAt(int inIndex) 627 { 628 return mBuffer.codePointAt(inIndex); 629 } 630 631 //-------------------------------------------------------------------------- 632 public int codePointBefore(int inIndex) 633 { 634 return mBuffer.codePointBefore(inIndex); 635 } 636 637 //-------------------------------------------------------------------------- 638 public int codePointCount(int inBeginIndex, int inEndIndex) 639 { 640 return mBuffer.codePointCount(inBeginIndex, inEndIndex); 641 } 642 643 //-------------------------------------------------------------------------- 644 public int offsetByCodePoints(int inIndex, int inCodePointOffset) 645 { 646 return mBuffer.offsetByCodePoints(inIndex, inCodePointOffset); 647 } 648 649 //-------------------------------------------------------------------------- 650 public StringBuilderPlus getChars(int inSrcBegin, int inSrcEnd, char[] inDest, int inDestBegin) 651 { 652 mBuffer.getChars(inSrcBegin, inSrcEnd, inDest, inDestBegin); 653 654 return this; 655 } 656 657 //-------------------------------------------------------------------------- 658 public StringBuilderPlus setCharAt(int inIndex, char inChar) 659 { 660 mBuffer.setCharAt(inIndex, inChar); 661 662 return this; 663 } 664 665 //-------------------------------------------------------------------------- 666 public String substring(int inStart) 667 { 668 return mBuffer.substring(inStart); 669 } 670 671 //-------------------------------------------------------------------------- 672 public String substring(int inStart, int inEnd) 673 { 674 return mBuffer.substring(inStart, inEnd); 675 } 676 677 //-------------------------------------------------------------------------- 678 public CharSequence subSequence(int inStart, int inEnd) 679 { 680 return mBuffer.subSequence(inStart, inEnd); 681 } 682 683 //########################################################################## 684 // PRIVATE METHODS 685 //########################################################################## 686 687 688 //-------------------------------------------------------------------------- 689 private void delimitIfNecessary() 690 { 691 if (length() > 0) 692 { 693 append(mDelimiter); 694 } 695 } 696 697 //-------------------------------------------------------------------------- 698 private CharSequence processAddedContentForCarriageReturns(CharSequence inContent) 699 { 700 StringBuilderPlus buffer = new StringBuilderPlus(inContent); 701 int index = buffer.indexOf("\r", 1); 702 while (index > 0) 703 { 704 int lastLineFeedIndex = buffer.substring(0, index).lastIndexOf('\n'); 705 buffer.replace(lastLineFeedIndex + 1, index + (lastLineFeedIndex < 0 ? 0 : 1), ""); 706 index = buffer.indexOf("\r", lastLineFeedIndex); 707 } 708 709 return buffer; 710 } 711 712}