001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.text; 018 019import java.io.IOException; 020import java.io.Reader; 021import java.io.Serializable; 022import java.io.Writer; 023import java.nio.CharBuffer; 024import java.util.Arrays; 025import java.util.Iterator; 026import java.util.List; 027import java.util.Objects; 028 029import org.apache.commons.lang3.ArrayUtils; 030import org.apache.commons.lang3.StringUtils; 031import org.apache.commons.text.matcher.StringMatcher; 032 033/** 034 * Builds a string from constituent parts providing a more flexible and powerful API than {@link StringBuffer} and 035 * {@link StringBuilder}. 036 * <p> 037 * The main differences from StringBuffer/StringBuilder are: 038 * </p> 039 * <ul> 040 * <li>Not synchronized</li> 041 * <li>Not final</li> 042 * <li>Subclasses have direct access to character array</li> 043 * <li>Additional methods 044 * <ul> 045 * <li>appendWithSeparators - adds an array of values, with a separator</li> 046 * <li>appendPadding - adds a length padding characters</li> 047 * <li>appendFixedLength - adds a fixed width field to the builder</li> 048 * <li>toCharArray/getChars - simpler ways to get a range of the character array</li> 049 * <li>delete - delete char or string</li> 050 * <li>replace - search and replace for a char or string</li> 051 * <li>leftString/rightString/midString - substring without exceptions</li> 052 * <li>contains - whether the builder contains a char or string</li> 053 * <li>size/clear/isEmpty - collections style API methods</li> 054 * </ul> 055 * </li> 056 * <li>Views 057 * <ul> 058 * <li>asTokenizer - uses the internal buffer as the source of a StrTokenizer</li> 059 * <li>asReader - uses the internal buffer as the source of a Reader</li> 060 * <li>asWriter - allows a Writer to write directly to the internal buffer</li> 061 * </ul> 062 * </li> 063 * </ul> 064 * <p> 065 * The aim has been to provide an API that mimics very closely what StringBuffer provides, but with additional methods. 066 * It should be noted that some edge cases, with invalid indices or null input, have been altered - see individual 067 * methods. The biggest of these changes is that by default, null will not output the text 'null'. This can be 068 * controlled by a property, {@link #setNullText(String)}. 069 * </p> 070 * <p> 071 * This class is called {@code TextStringBuilder} instead of {@code StringBuilder} to avoid clashing with 072 * {@link StringBuilder}. 073 * </p> 074 * 075 * @since 1.3 076 */ 077public class TextStringBuilder implements CharSequence, Appendable, Serializable, Builder<String> { 078 079 /** 080 * Inner class to allow StrBuilder to operate as a reader. 081 */ 082 class TextStringBuilderReader extends Reader { 083 084 /** The last mark position. */ 085 private int mark; 086 087 /** The current stream position. */ 088 private int pos; 089 090 /** 091 * Default constructor. 092 */ 093 TextStringBuilderReader() { 094 } 095 096 /** {@inheritDoc} */ 097 @Override 098 public void close() { 099 // do nothing 100 } 101 102 /** {@inheritDoc} */ 103 @Override 104 public void mark(final int readAheadLimit) { 105 mark = pos; 106 } 107 108 /** {@inheritDoc} */ 109 @Override 110 public boolean markSupported() { 111 return true; 112 } 113 114 /** {@inheritDoc} */ 115 @Override 116 public int read() { 117 if (!ready()) { 118 return -1; 119 } 120 return TextStringBuilder.this.charAt(pos++); 121 } 122 123 /** {@inheritDoc} */ 124 @Override 125 public int read(final char[] b, final int off, int len) { 126 if (off < 0 || len < 0 || off > b.length || off + len > b.length || off + len < 0) { 127 throw new IndexOutOfBoundsException(); 128 } 129 if (len == 0) { 130 return 0; 131 } 132 if (pos >= TextStringBuilder.this.size()) { 133 return -1; 134 } 135 if (pos + len > size()) { 136 len = TextStringBuilder.this.size() - pos; 137 } 138 TextStringBuilder.this.getChars(pos, pos + len, b, off); 139 pos += len; 140 return len; 141 } 142 143 /** {@inheritDoc} */ 144 @Override 145 public boolean ready() { 146 return pos < TextStringBuilder.this.size(); 147 } 148 149 /** {@inheritDoc} */ 150 @Override 151 public void reset() { 152 pos = mark; 153 } 154 155 /** {@inheritDoc} */ 156 @Override 157 public long skip(long n) { 158 if (pos + n > TextStringBuilder.this.size()) { 159 n = TextStringBuilder.this.size() - pos; 160 } 161 if (n < 0) { 162 return 0; 163 } 164 pos = Math.addExact(pos, Math.toIntExact(n)); 165 return n; 166 } 167 } 168 169 /** 170 * Inner class to allow StrBuilder to operate as a tokenizer. 171 */ 172 class TextStringBuilderTokenizer extends StringTokenizer { 173 174 /** 175 * Default constructor. 176 */ 177 TextStringBuilderTokenizer() { 178 } 179 180 /** {@inheritDoc} */ 181 @Override 182 public String getContent() { 183 final String str = super.getContent(); 184 if (str == null) { 185 return TextStringBuilder.this.toString(); 186 } 187 return str; 188 } 189 190 /** {@inheritDoc} */ 191 @Override 192 protected List<String> tokenize(final char[] chars, final int offset, final int count) { 193 if (chars == null) { 194 return super.tokenize(TextStringBuilder.this.getBuffer(), 0, TextStringBuilder.this.size()); 195 } 196 return super.tokenize(chars, offset, count); 197 } 198 } 199 200 /** 201 * Inner class to allow StrBuilder to operate as a writer. 202 */ 203 class TextStringBuilderWriter extends Writer { 204 205 /** 206 * Default constructor. 207 */ 208 TextStringBuilderWriter() { 209 } 210 211 /** {@inheritDoc} */ 212 @Override 213 public void close() { 214 // do nothing 215 } 216 217 /** {@inheritDoc} */ 218 @Override 219 public void flush() { 220 // do nothing 221 } 222 223 /** {@inheritDoc} */ 224 @Override 225 public void write(final char[] cbuf) { 226 TextStringBuilder.this.append(cbuf); 227 } 228 229 /** {@inheritDoc} */ 230 @Override 231 public void write(final char[] cbuf, final int off, final int len) { 232 TextStringBuilder.this.append(cbuf, off, len); 233 } 234 235 /** {@inheritDoc} */ 236 @Override 237 public void write(final int c) { 238 TextStringBuilder.this.append((char) c); 239 } 240 241 /** {@inheritDoc} */ 242 @Override 243 public void write(final String str) { 244 TextStringBuilder.this.append(str); 245 } 246 247 /** {@inheritDoc} */ 248 @Override 249 public void write(final String str, final int off, final int len) { 250 TextStringBuilder.this.append(str, off, len); 251 } 252 } 253 254 /** The space character. */ 255 private static final char SPACE = ' '; 256 257 /** 258 * The extra capacity for new builders. 259 */ 260 static final int CAPACITY = 32; 261 262 /** 263 * End-Of-Stream. 264 */ 265 private static final int EOS = -1; 266 267 /** 268 * The size of the string {@code "false"}. 269 */ 270 private static final int FALSE_STRING_SIZE = Boolean.FALSE.toString().length(); 271 272 /** 273 * Required for serialization support. 274 * 275 * @see java.io.Serializable 276 */ 277 private static final long serialVersionUID = 1L; 278 279 /** 280 * The size of the string {@code "true"}. 281 */ 282 private static final int TRUE_STRING_SIZE = Boolean.TRUE.toString().length(); 283 284 /** 285 * Constructs an instance from a reference to a character array. Changes to the input chars are reflected in this 286 * instance until the internal buffer needs to be reallocated. Using a reference to an array allows the instance to 287 * be initialized without copying the input array. 288 * 289 * @param initialBuffer The initial array that will back the new builder. 290 * @return A new instance. 291 * @since 1.9 292 */ 293 public static TextStringBuilder wrap(final char[] initialBuffer) { 294 Objects.requireNonNull(initialBuffer, "initialBuffer"); 295 return new TextStringBuilder(initialBuffer, initialBuffer.length); 296 } 297 298 /** 299 * Constructs an instance from a reference to a character array. Changes to the input chars are reflected in this 300 * instance until the internal buffer needs to be reallocated. Using a reference to an array allows the instance to 301 * be initialized without copying the input array. 302 * 303 * @param initialBuffer The initial array that will back the new builder. 304 * @param length The length of the subarray to be used; must be non-negative and no larger than 305 * {@code initialBuffer.length}. The new builder's size will be set to {@code length}. 306 * @return A new instance. 307 * @since 1.9 308 */ 309 public static TextStringBuilder wrap(final char[] initialBuffer, final int length) { 310 return new TextStringBuilder(initialBuffer, length); 311 } 312 313 /** Internal data storage. */ 314 private char[] buffer; 315 316 /** The new line. */ 317 private String newLine; 318 319 /** The null text. */ 320 private String nullText; 321 322 /** Incremented when the buffer is reallocated. */ 323 private int reallocations; 324 325 /** Current size of the buffer. */ 326 private int size; 327 328 /** 329 * Constructs an empty builder with an initial capacity of 32 characters. 330 */ 331 public TextStringBuilder() { 332 this(CAPACITY); 333 } 334 335 /** 336 * Constructs an instance from a reference to a character array. 337 * 338 * @param initialBuffer a reference to a character array, must not be null. 339 * @param length The length of the subarray to be used; must be non-negative and no larger than 340 * {@code initialBuffer.length}. The new builder's size will be set to {@code length}. 341 * @throws NullPointerException If {@code initialBuffer} is null. 342 * @throws IllegalArgumentException if {@code length} is bad. 343 */ 344 private TextStringBuilder(final char[] initialBuffer, final int length) { 345 this.buffer = Objects.requireNonNull(initialBuffer, "initialBuffer"); 346 if (length < 0 || length > initialBuffer.length) { 347 throw new IllegalArgumentException("initialBuffer.length=" + initialBuffer.length + ", length=" + length); 348 } 349 this.size = length; 350 } 351 352 /** 353 * Constructs an instance from a character sequence, allocating 32 extra characters for growth. 354 * 355 * @param seq the string to copy, null treated as blank string 356 * @since 1.9 357 */ 358 public TextStringBuilder(final CharSequence seq) { 359 this(StringUtils.length(seq) + CAPACITY); 360 if (seq != null) { 361 append(seq); 362 } 363 } 364 365 /** 366 * Constructs an instance with the specified initial capacity. 367 * 368 * @param initialCapacity the initial capacity, zero or less will be converted to 32 369 */ 370 public TextStringBuilder(final int initialCapacity) { 371 buffer = new char[initialCapacity <= 0 ? CAPACITY : initialCapacity]; 372 } 373 374 /** 375 * Constructs an instance from a string, allocating 32 extra characters for growth. 376 * 377 * @param str the string to copy, null treated as blank string 378 */ 379 public TextStringBuilder(final String str) { 380 this(StringUtils.length(str) + CAPACITY); 381 if (str != null) { 382 append(str); 383 } 384 } 385 386 /** 387 * Appends a boolean value to the string builder. 388 * 389 * @param value the value to append 390 * @return this, to enable chaining 391 */ 392 public TextStringBuilder append(final boolean value) { 393 if (value) { 394 ensureCapacity(size + TRUE_STRING_SIZE); 395 appendTrue(size); 396 } else { 397 ensureCapacity(size + FALSE_STRING_SIZE); 398 appendFalse(size); 399 } 400 return this; 401 } 402 403 /** 404 * Appends a char value to the string builder. 405 * 406 * @param ch the value to append 407 * @return this, to enable chaining 408 */ 409 @Override 410 public TextStringBuilder append(final char ch) { 411 final int len = length(); 412 ensureCapacity(len + 1); 413 buffer[size++] = ch; 414 return this; 415 } 416 417 /** 418 * Appends a char array to the string builder. Appending null will call {@link #appendNull()}. 419 * 420 * @param chars the char array to append 421 * @return this, to enable chaining 422 */ 423 public TextStringBuilder append(final char[] chars) { 424 if (chars == null) { 425 return appendNull(); 426 } 427 final int strLen = chars.length; 428 if (strLen > 0) { 429 final int len = length(); 430 ensureCapacity(len + strLen); 431 System.arraycopy(chars, 0, buffer, len, strLen); 432 size += strLen; 433 } 434 return this; 435 } 436 437 /** 438 * Appends a char array to the string builder. Appending null will call {@link #appendNull()}. 439 * 440 * @param chars the char array to append 441 * @param startIndex the start index, inclusive, must be valid 442 * @param length the length to append, must be valid 443 * @return this, to enable chaining 444 * @throws StringIndexOutOfBoundsException if {@code startIndex} is not in the 445 * range {@code 0 <= startIndex <= chars.length} 446 * @throws StringIndexOutOfBoundsException if {@code length < 0} 447 * @throws StringIndexOutOfBoundsException if {@code startIndex + length > chars.length} 448 */ 449 public TextStringBuilder append(final char[] chars, final int startIndex, final int length) { 450 if (chars == null) { 451 return appendNull(); 452 } 453 if (startIndex < 0 || startIndex > chars.length) { 454 throw new StringIndexOutOfBoundsException("Invalid startIndex: " + length); 455 } 456 if (length < 0 || startIndex + length > chars.length) { 457 throw new StringIndexOutOfBoundsException("Invalid length: " + length); 458 } 459 if (length > 0) { 460 final int len = length(); 461 ensureCapacity(len + length); 462 System.arraycopy(chars, startIndex, buffer, len, length); 463 size += length; 464 } 465 return this; 466 } 467 468 /** 469 * Appends the contents of a char buffer to this string builder. Appending null will call {@link #appendNull()}. 470 * 471 * @param str the char buffer to append 472 * @return this, to enable chaining 473 */ 474 public TextStringBuilder append(final CharBuffer str) { 475 return append(str, 0, StringUtils.length(str)); 476 } 477 478 /** 479 * Appends the contents of a char buffer to this string builder. Appending null will call {@link #appendNull()}. 480 * 481 * @param buf the char buffer to append 482 * @param startIndex the start index, inclusive, must be valid 483 * @param length the length to append, must be valid 484 * @return this, to enable chaining 485 */ 486 public TextStringBuilder append(final CharBuffer buf, final int startIndex, final int length) { 487 if (buf == null) { 488 return appendNull(); 489 } 490 if (buf.hasArray()) { 491 final int totalLength = buf.remaining(); 492 if (startIndex < 0 || startIndex > totalLength) { 493 throw new StringIndexOutOfBoundsException("startIndex must be valid"); 494 } 495 if (length < 0 || startIndex + length > totalLength) { 496 throw new StringIndexOutOfBoundsException("length must be valid"); 497 } 498 final int len = length(); 499 ensureCapacity(len + length); 500 System.arraycopy(buf.array(), buf.arrayOffset() + buf.position() + startIndex, buffer, len, length); 501 size += length; 502 } else { 503 append(buf.toString(), startIndex, length); 504 } 505 return this; 506 } 507 508 /** 509 * Appends a CharSequence to this string builder. Appending null will call {@link #appendNull()}. 510 * 511 * @param seq the CharSequence to append 512 * @return this, to enable chaining 513 */ 514 @Override 515 public TextStringBuilder append(final CharSequence seq) { 516 if (seq == null) { 517 return appendNull(); 518 } 519 if (seq instanceof TextStringBuilder) { 520 return append((TextStringBuilder) seq); 521 } 522 if (seq instanceof StringBuilder) { 523 return append((StringBuilder) seq); 524 } 525 if (seq instanceof StringBuffer) { 526 return append((StringBuffer) seq); 527 } 528 if (seq instanceof CharBuffer) { 529 return append((CharBuffer) seq); 530 } 531 return append(seq.toString()); 532 } 533 534 /** 535 * Appends part of a CharSequence to this string builder. Appending null will call {@link #appendNull()}. 536 * 537 * @param seq the CharSequence to append 538 * @param startIndex the start index, inclusive, must be valid 539 * @param endIndex the end index, exclusive, must be valid 540 * @return this, to enable chaining 541 */ 542 @Override 543 public TextStringBuilder append(final CharSequence seq, final int startIndex, final int endIndex) { 544 if (seq == null) { 545 return appendNull(); 546 } 547 if (endIndex <= 0) { 548 throw new StringIndexOutOfBoundsException("endIndex must be valid"); 549 } 550 if (startIndex >= endIndex) { 551 throw new StringIndexOutOfBoundsException("endIndex must be greater than startIndex"); 552 } 553 return append(seq.toString(), startIndex, endIndex - startIndex); 554 } 555 556 /** 557 * Appends a double value to the string builder using {@code String.valueOf}. 558 * 559 * @param value the value to append 560 * @return this, to enable chaining 561 */ 562 public TextStringBuilder append(final double value) { 563 return append(String.valueOf(value)); 564 } 565 566 /** 567 * Appends a float value to the string builder using {@code String.valueOf}. 568 * 569 * @param value the value to append 570 * @return this, to enable chaining 571 */ 572 public TextStringBuilder append(final float value) { 573 return append(String.valueOf(value)); 574 } 575 576 /** 577 * Appends an int value to the string builder using {@code String.valueOf}. 578 * 579 * @param value the value to append 580 * @return this, to enable chaining 581 */ 582 public TextStringBuilder append(final int value) { 583 return append(String.valueOf(value)); 584 } 585 586 /** 587 * Appends a long value to the string builder using {@code String.valueOf}. 588 * 589 * @param value the value to append 590 * @return this, to enable chaining 591 */ 592 public TextStringBuilder append(final long value) { 593 return append(String.valueOf(value)); 594 } 595 596 /** 597 * Appends an object to this string builder. Appending null will call {@link #appendNull()}. 598 * 599 * @param obj the object to append 600 * @return this, to enable chaining 601 */ 602 public TextStringBuilder append(final Object obj) { 603 if (obj == null) { 604 return appendNull(); 605 } 606 if (obj instanceof CharSequence) { 607 return append((CharSequence) obj); 608 } 609 return append(obj.toString()); 610 } 611 612 /** 613 * Appends a string to this string builder. Appending null will call {@link #appendNull()}. 614 * 615 * @param str the string to append 616 * @return this, to enable chaining 617 */ 618 public TextStringBuilder append(final String str) { 619 return append(str, 0, StringUtils.length(str)); 620 } 621 622 /** 623 * Appends part of a string to this string builder. Appending null will call {@link #appendNull()}. 624 * 625 * @param str the string to append 626 * @param startIndex the start index, inclusive, must be valid 627 * @param length the length to append, must be valid 628 * @return this, to enable chaining 629 * @throws StringIndexOutOfBoundsException if {@code startIndex} is not in the 630 * range {@code 0 <= startIndex <= str.length()} 631 * @throws StringIndexOutOfBoundsException if {@code length < 0} 632 * @throws StringIndexOutOfBoundsException if {@code startIndex + length > str.length()} 633 */ 634 public TextStringBuilder append(final String str, final int startIndex, final int length) { 635 if (str == null) { 636 return appendNull(); 637 } 638 if (startIndex < 0 || startIndex > str.length()) { 639 throw new StringIndexOutOfBoundsException("startIndex must be valid"); 640 } 641 if (length < 0 || startIndex + length > str.length()) { 642 throw new StringIndexOutOfBoundsException("length must be valid"); 643 } 644 if (length > 0) { 645 final int len = length(); 646 ensureCapacity(len + length); 647 str.getChars(startIndex, startIndex + length, buffer, len); 648 size += length; 649 } 650 return this; 651 } 652 653 /** 654 * Calls {@link String#format(String, Object...)} and appends the result. 655 * 656 * @param format the format string 657 * @param objs the objects to use in the format string 658 * @return {@code this} to enable chaining 659 * @see String#format(String, Object...) 660 */ 661 public TextStringBuilder append(final String format, final Object... objs) { 662 return append(String.format(format, objs)); 663 } 664 665 /** 666 * Appends a string buffer to this string builder. Appending null will call {@link #appendNull()}. 667 * 668 * @param str the string buffer to append 669 * @return this, to enable chaining 670 */ 671 public TextStringBuilder append(final StringBuffer str) { 672 return append(str, 0, StringUtils.length(str)); 673 } 674 675 /** 676 * Appends part of a string buffer to this string builder. Appending null will call {@link #appendNull()}. 677 * 678 * @param str the string to append 679 * @param startIndex the start index, inclusive, must be valid 680 * @param length the length to append, must be valid 681 * @return this, to enable chaining 682 */ 683 public TextStringBuilder append(final StringBuffer str, final int startIndex, final int length) { 684 if (str == null) { 685 return appendNull(); 686 } 687 if (startIndex < 0 || startIndex > str.length()) { 688 throw new StringIndexOutOfBoundsException("startIndex must be valid"); 689 } 690 if (length < 0 || startIndex + length > str.length()) { 691 throw new StringIndexOutOfBoundsException("length must be valid"); 692 } 693 if (length > 0) { 694 final int len = length(); 695 ensureCapacity(len + length); 696 str.getChars(startIndex, startIndex + length, buffer, len); 697 size += length; 698 } 699 return this; 700 } 701 702 /** 703 * Appends a StringBuilder to this string builder. Appending null will call {@link #appendNull()}. 704 * 705 * @param str the StringBuilder to append 706 * @return this, to enable chaining 707 */ 708 public TextStringBuilder append(final StringBuilder str) { 709 return append(str, 0, StringUtils.length(str)); 710 } 711 712 /** 713 * Appends part of a StringBuilder to this string builder. Appending null will call {@link #appendNull()}. 714 * 715 * @param str the StringBuilder to append 716 * @param startIndex the start index, inclusive, must be valid 717 * @param length the length to append, must be valid 718 * @return this, to enable chaining 719 */ 720 public TextStringBuilder append(final StringBuilder str, final int startIndex, final int length) { 721 if (str == null) { 722 return appendNull(); 723 } 724 if (startIndex < 0 || startIndex > str.length()) { 725 throw new StringIndexOutOfBoundsException("startIndex must be valid"); 726 } 727 if (length < 0 || startIndex + length > str.length()) { 728 throw new StringIndexOutOfBoundsException("length must be valid"); 729 } 730 if (length > 0) { 731 final int len = length(); 732 ensureCapacity(len + length); 733 str.getChars(startIndex, startIndex + length, buffer, len); 734 size += length; 735 } 736 return this; 737 } 738 739 /** 740 * Appends another string builder to this string builder. Appending null will call {@link #appendNull()}. 741 * 742 * @param str the string builder to append 743 * @return this, to enable chaining 744 */ 745 public TextStringBuilder append(final TextStringBuilder str) { 746 return append(str, 0, StringUtils.length(str)); 747 } 748 749 /** 750 * Appends part of a string builder to this string builder. Appending null will call {@link #appendNull()}. 751 * 752 * @param str the string to append 753 * @param startIndex the start index, inclusive, must be valid 754 * @param length the length to append, must be valid 755 * @return this, to enable chaining 756 */ 757 public TextStringBuilder append(final TextStringBuilder str, final int startIndex, final int length) { 758 if (str == null) { 759 return appendNull(); 760 } 761 if (startIndex < 0 || startIndex > str.length()) { 762 throw new StringIndexOutOfBoundsException("startIndex must be valid"); 763 } 764 if (length < 0 || startIndex + length > str.length()) { 765 throw new StringIndexOutOfBoundsException("length must be valid"); 766 } 767 if (length > 0) { 768 final int len = length(); 769 ensureCapacity(len + length); 770 str.getChars(startIndex, startIndex + length, buffer, len); 771 size += length; 772 } 773 return this; 774 } 775 776 /** 777 * Appends each item in an iterable to the builder without any separators. Appending a null iterable will have no 778 * effect. Each object is appended using {@link #append(Object)}. 779 * 780 * @param iterable the iterable to append 781 * @return this, to enable chaining 782 */ 783 public TextStringBuilder appendAll(final Iterable<?> iterable) { 784 if (iterable != null) { 785 iterable.forEach(this::append); 786 } 787 return this; 788 } 789 790 /** 791 * Appends each item in an iterator to the builder without any separators. Appending a null iterator will have no 792 * effect. Each object is appended using {@link #append(Object)}. 793 * 794 * @param it the iterator to append 795 * @return this, to enable chaining 796 */ 797 public TextStringBuilder appendAll(final Iterator<?> it) { 798 if (it != null) { 799 it.forEachRemaining(this::append); 800 } 801 return this; 802 } 803 804 /** 805 * Appends each item in an array to the builder without any separators. Appending a null array will have no effect. 806 * Each object is appended using {@link #append(Object)}. 807 * 808 * @param <T> the element type 809 * @param array the array to append 810 * @return this, to enable chaining 811 */ 812 public <T> TextStringBuilder appendAll(@SuppressWarnings("unchecked") final T... array) { 813 /* 814 * @SuppressWarnings used to hide warning about vararg usage. We cannot use @SafeVarargs, since this method is 815 * not final. Using @SuppressWarnings is fine, because it isn't inherited by subclasses, so each subclass must 816 * vouch for itself whether its use of 'array' is safe. 817 */ 818 if (array != null && array.length > 0) { 819 for (final Object element : array) { 820 append(element); 821 } 822 } 823 return this; 824 } 825 826 /** Appends {@code "false"}. */ 827 private void appendFalse(int index) { 828 buffer[index++] = 'f'; 829 buffer[index++] = 'a'; 830 buffer[index++] = 'l'; 831 buffer[index++] = 's'; 832 buffer[index] = 'e'; 833 size += FALSE_STRING_SIZE; 834 } 835 836 /** 837 * Appends an object to the builder padding on the left to a fixed width. The {@code String.valueOf} of the 838 * {@code int} value is used. If the formatted value is larger than the length, the left hand side is lost. 839 * 840 * @param value the value to append 841 * @param width the fixed field width, zero or negative has no effect 842 * @param padChar the pad character to use 843 * @return this, to enable chaining 844 */ 845 public TextStringBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) { 846 return appendFixedWidthPadLeft(String.valueOf(value), width, padChar); 847 } 848 849 /** 850 * Appends an object to the builder padding on the left to a fixed width. The {@code toString} of the object is 851 * used. If the object is larger than the length, the left hand side is lost. If the object is null, the null text 852 * value is used. 853 * 854 * @param obj the object to append, null uses null text 855 * @param width the fixed field width, zero or negative has no effect 856 * @param padChar the pad character to use 857 * @return this, to enable chaining 858 */ 859 public TextStringBuilder appendFixedWidthPadLeft(final Object obj, final int width, final char padChar) { 860 if (width > 0) { 861 ensureCapacity(size + width); 862 String str = obj == null ? getNullText() : obj.toString(); 863 if (str == null) { 864 str = StringUtils.EMPTY; 865 } 866 final int strLen = str.length(); 867 if (strLen >= width) { 868 str.getChars(strLen - width, strLen, buffer, size); 869 } else { 870 final int padLen = width - strLen; 871 for (int i = 0; i < padLen; i++) { 872 buffer[size + i] = padChar; 873 } 874 str.getChars(0, strLen, buffer, size + padLen); 875 } 876 size += width; 877 } 878 return this; 879 } 880 881 /** 882 * Appends an object to the builder padding on the right to a fixed length. The {@code String.valueOf} of the 883 * {@code int} value is used. If the object is larger than the length, the right hand side is lost. 884 * 885 * @param value the value to append 886 * @param width the fixed field width, zero or negative has no effect 887 * @param padChar the pad character to use 888 * @return this, to enable chaining 889 */ 890 public TextStringBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) { 891 return appendFixedWidthPadRight(String.valueOf(value), width, padChar); 892 } 893 894 /** 895 * Appends an object to the builder padding on the right to a fixed length. The {@code toString} of the object is 896 * used. If the object is larger than the length, the right hand side is lost. If the object is null, null text 897 * value is used. 898 * 899 * @param obj the object to append, null uses null text 900 * @param width the fixed field width, zero or negative has no effect 901 * @param padChar the pad character to use 902 * @return this, to enable chaining 903 */ 904 public TextStringBuilder appendFixedWidthPadRight(final Object obj, final int width, final char padChar) { 905 if (width > 0) { 906 ensureCapacity(size + width); 907 String str = obj == null ? getNullText() : obj.toString(); 908 if (str == null) { 909 str = StringUtils.EMPTY; 910 } 911 final int strLen = str.length(); 912 if (strLen >= width) { 913 str.getChars(0, width, buffer, size); 914 } else { 915 final int padLen = width - strLen; 916 str.getChars(0, strLen, buffer, size); 917 for (int i = 0; i < padLen; i++) { 918 buffer[size + strLen + i] = padChar; 919 } 920 } 921 size += width; 922 } 923 return this; 924 } 925 926 /** 927 * Appends a boolean value followed by a new line to the string builder. 928 * 929 * @param value the value to append 930 * @return this, to enable chaining 931 */ 932 public TextStringBuilder appendln(final boolean value) { 933 return append(value).appendNewLine(); 934 } 935 936 /** 937 * Appends a char value followed by a new line to the string builder. 938 * 939 * @param ch the value to append 940 * @return this, to enable chaining 941 */ 942 public TextStringBuilder appendln(final char ch) { 943 return append(ch).appendNewLine(); 944 } 945 946 /** 947 * Appends a char array followed by a new line to the string builder. Appending null will call 948 * {@link #appendNull()}. 949 * 950 * @param chars the char array to append 951 * @return this, to enable chaining 952 */ 953 public TextStringBuilder appendln(final char[] chars) { 954 return append(chars).appendNewLine(); 955 } 956 957 /** 958 * Appends a char array followed by a new line to the string builder. Appending null will call 959 * {@link #appendNull()}. 960 * 961 * @param chars the char array to append 962 * @param startIndex the start index, inclusive, must be valid 963 * @param length the length to append, must be valid 964 * @return this, to enable chaining 965 */ 966 public TextStringBuilder appendln(final char[] chars, final int startIndex, final int length) { 967 return append(chars, startIndex, length).appendNewLine(); 968 } 969 970 /** 971 * Appends a double value followed by a new line to the string builder using {@code String.valueOf}. 972 * 973 * @param value the value to append 974 * @return this, to enable chaining 975 */ 976 public TextStringBuilder appendln(final double value) { 977 return append(value).appendNewLine(); 978 } 979 980 /** 981 * Appends a float value followed by a new line to the string builder using {@code String.valueOf}. 982 * 983 * @param value the value to append 984 * @return this, to enable chaining 985 */ 986 public TextStringBuilder appendln(final float value) { 987 return append(value).appendNewLine(); 988 } 989 990 /** 991 * Appends an int value followed by a new line to the string builder using {@code String.valueOf}. 992 * 993 * @param value the value to append 994 * @return this, to enable chaining 995 */ 996 public TextStringBuilder appendln(final int value) { 997 return append(value).appendNewLine(); 998 } 999 1000 /** 1001 * Appends a long value followed by a new line to the string builder using {@code String.valueOf}. 1002 * 1003 * @param value the value to append 1004 * @return this, to enable chaining 1005 */ 1006 public TextStringBuilder appendln(final long value) { 1007 return append(value).appendNewLine(); 1008 } 1009 1010 /** 1011 * Appends an object followed by a new line to this string builder. Appending null will call {@link #appendNull()}. 1012 * 1013 * @param obj the object to append 1014 * @return this, to enable chaining 1015 */ 1016 public TextStringBuilder appendln(final Object obj) { 1017 return append(obj).appendNewLine(); 1018 } 1019 1020 /** 1021 * Appends a string followed by a new line to this string builder. Appending null will call {@link #appendNull()}. 1022 * 1023 * @param str the string to append 1024 * @return this, to enable chaining 1025 */ 1026 public TextStringBuilder appendln(final String str) { 1027 return append(str).appendNewLine(); 1028 } 1029 1030 /** 1031 * Appends part of a string followed by a new line to this string builder. Appending null will call 1032 * {@link #appendNull()}. 1033 * 1034 * @param str the string to append 1035 * @param startIndex the start index, inclusive, must be valid 1036 * @param length the length to append, must be valid 1037 * @return this, to enable chaining 1038 */ 1039 public TextStringBuilder appendln(final String str, final int startIndex, final int length) { 1040 return append(str, startIndex, length).appendNewLine(); 1041 } 1042 1043 /** 1044 * Calls {@link String#format(String, Object...)} and appends the result. 1045 * 1046 * @param format the format string 1047 * @param objs the objects to use in the format string 1048 * @return {@code this} to enable chaining 1049 * @see String#format(String, Object...) 1050 */ 1051 public TextStringBuilder appendln(final String format, final Object... objs) { 1052 return append(format, objs).appendNewLine(); 1053 } 1054 1055 /** 1056 * Appends a string buffer followed by a new line to this string builder. Appending null will call 1057 * {@link #appendNull()}. 1058 * 1059 * @param str the string buffer to append 1060 * @return this, to enable chaining 1061 */ 1062 public TextStringBuilder appendln(final StringBuffer str) { 1063 return append(str).appendNewLine(); 1064 } 1065 1066 /** 1067 * Appends part of a string buffer followed by a new line to this string builder. Appending null will call 1068 * {@link #appendNull()}. 1069 * 1070 * @param str the string to append 1071 * @param startIndex the start index, inclusive, must be valid 1072 * @param length the length to append, must be valid 1073 * @return this, to enable chaining 1074 */ 1075 public TextStringBuilder appendln(final StringBuffer str, final int startIndex, final int length) { 1076 return append(str, startIndex, length).appendNewLine(); 1077 } 1078 1079 /** 1080 * Appends a string builder followed by a new line to this string builder. Appending null will call 1081 * {@link #appendNull()}. 1082 * 1083 * @param str the string builder to append 1084 * @return this, to enable chaining 1085 */ 1086 public TextStringBuilder appendln(final StringBuilder str) { 1087 return append(str).appendNewLine(); 1088 } 1089 1090 /** 1091 * Appends part of a string builder followed by a new line to this string builder. Appending null will call 1092 * {@link #appendNull()}. 1093 * 1094 * @param str the string builder to append 1095 * @param startIndex the start index, inclusive, must be valid 1096 * @param length the length to append, must be valid 1097 * @return this, to enable chaining 1098 */ 1099 public TextStringBuilder appendln(final StringBuilder str, final int startIndex, final int length) { 1100 return append(str, startIndex, length).appendNewLine(); 1101 } 1102 1103 /** 1104 * Appends another string builder followed by a new line to this string builder. Appending null will call 1105 * {@link #appendNull()}. 1106 * 1107 * @param str the string builder to append 1108 * @return this, to enable chaining 1109 */ 1110 public TextStringBuilder appendln(final TextStringBuilder str) { 1111 return append(str).appendNewLine(); 1112 } 1113 1114 /** 1115 * Appends part of a string builder followed by a new line to this string builder. Appending null will call 1116 * {@link #appendNull()}. 1117 * 1118 * @param str the string to append 1119 * @param startIndex the start index, inclusive, must be valid 1120 * @param length the length to append, must be valid 1121 * @return this, to enable chaining 1122 */ 1123 public TextStringBuilder appendln(final TextStringBuilder str, final int startIndex, final int length) { 1124 return append(str, startIndex, length).appendNewLine(); 1125 } 1126 1127 /** 1128 * Appends the new line string to this string builder. 1129 * <p> 1130 * The new line string can be altered using {@link #setNewLineText(String)}. This might be used to force the output 1131 * to always use Unix line endings even when on Windows. 1132 * </p> 1133 * 1134 * @return this, to enable chaining 1135 */ 1136 public TextStringBuilder appendNewLine() { 1137 if (newLine == null) { 1138 append(System.lineSeparator()); 1139 return this; 1140 } 1141 return append(newLine); 1142 } 1143 1144 /** 1145 * Appends the text representing {@code null} to this string builder. 1146 * 1147 * @return this, to enable chaining 1148 */ 1149 public TextStringBuilder appendNull() { 1150 if (nullText == null) { 1151 return this; 1152 } 1153 return append(nullText); 1154 } 1155 1156 /** 1157 * Appends the pad character to the builder the specified number of times. 1158 * 1159 * @param length the length to append, negative means no append 1160 * @param padChar the character to append 1161 * @return this, to enable chaining 1162 */ 1163 public TextStringBuilder appendPadding(final int length, final char padChar) { 1164 if (length >= 0) { 1165 ensureCapacity(size + length); 1166 for (int i = 0; i < length; i++) { 1167 buffer[size++] = padChar; 1168 } 1169 } 1170 return this; 1171 } 1172 1173 /** 1174 * Appends a separator if the builder is currently non-empty. The separator is appended using {@link #append(char)}. 1175 * <p> 1176 * This method is useful for adding a separator each time around the loop except the first. 1177 * </p> 1178 * 1179 * <pre> 1180 * for (Iterator it = list.iterator(); it.hasNext();) { 1181 * appendSeparator(','); 1182 * append(it.next()); 1183 * } 1184 * </pre> 1185 * 1186 * <p> 1187 * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}. 1188 * </p> 1189 * 1190 * @param separator the separator to use 1191 * @return this, to enable chaining 1192 */ 1193 public TextStringBuilder appendSeparator(final char separator) { 1194 if (isNotEmpty()) { 1195 append(separator); 1196 } 1197 return this; 1198 } 1199 1200 /** 1201 * Appends one of both separators to the builder If the builder is currently empty it will append the 1202 * defaultIfEmpty-separator Otherwise it will append the standard-separator 1203 * 1204 * The separator is appended using {@link #append(char)}. 1205 * 1206 * @param standard the separator if builder is not empty 1207 * @param defaultIfEmpty the separator if builder is empty 1208 * @return this, to enable chaining 1209 */ 1210 public TextStringBuilder appendSeparator(final char standard, final char defaultIfEmpty) { 1211 if (isEmpty()) { 1212 append(defaultIfEmpty); 1213 } else { 1214 append(standard); 1215 } 1216 return this; 1217 } 1218 1219 /** 1220 * Appends a separator to the builder if the loop index is greater than zero. The separator is appended using 1221 * {@link #append(char)}. 1222 * <p> 1223 * This method is useful for adding a separator each time around the loop except the first. 1224 * </p> 1225 * 1226 * <pre> 1227 * for (int i = 0; i < list.size(); i++) { 1228 * appendSeparator(",", i); 1229 * append(list.get(i)); 1230 * } 1231 * </pre> 1232 * 1233 * <p> 1234 * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}. 1235 * </p> 1236 * 1237 * @param separator the separator to use 1238 * @param loopIndex the loop index 1239 * @return this, to enable chaining 1240 */ 1241 public TextStringBuilder appendSeparator(final char separator, final int loopIndex) { 1242 if (loopIndex > 0) { 1243 append(separator); 1244 } 1245 return this; 1246 } 1247 1248 /** 1249 * Appends a separator if the builder is currently non-empty. Appending a null separator will have no effect. The 1250 * separator is appended using {@link #append(String)}. 1251 * <p> 1252 * This method is useful for adding a separator each time around the loop except the first. 1253 * </p> 1254 * 1255 * <pre> 1256 * for (Iterator it = list.iterator(); it.hasNext();) { 1257 * appendSeparator(","); 1258 * append(it.next()); 1259 * } 1260 * </pre> 1261 * 1262 * <p> 1263 * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}. 1264 * </p> 1265 * 1266 * @param separator the separator to use, null means no separator 1267 * @return this, to enable chaining 1268 */ 1269 public TextStringBuilder appendSeparator(final String separator) { 1270 return appendSeparator(separator, null); 1271 } 1272 1273 /** 1274 * Appends a separator to the builder if the loop index is greater than zero. Appending a null separator will have 1275 * no effect. The separator is appended using {@link #append(String)}. 1276 * <p> 1277 * This method is useful for adding a separator each time around the loop except the first. 1278 * </p> 1279 * 1280 * <pre> 1281 * for (int i = 0; i < list.size(); i++) { 1282 * appendSeparator(",", i); 1283 * append(list.get(i)); 1284 * } 1285 * </pre> 1286 * 1287 * <p> 1288 * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}. 1289 * </p> 1290 * 1291 * @param separator the separator to use, null means no separator 1292 * @param loopIndex the loop index 1293 * @return this, to enable chaining 1294 */ 1295 public TextStringBuilder appendSeparator(final String separator, final int loopIndex) { 1296 if (separator != null && loopIndex > 0) { 1297 append(separator); 1298 } 1299 return this; 1300 } 1301 1302 /** 1303 * Appends one of both separators to the StrBuilder. If the builder is currently empty it will append the 1304 * defaultIfEmpty-separator Otherwise it will append the standard-separator 1305 * 1306 * Appending a null separator will have no effect. The separator is appended using {@link #append(String)}. 1307 * <p> 1308 * This method is for example useful for constructing queries 1309 * </p> 1310 * 1311 * <pre> 1312 * StrBuilder whereClause = new StrBuilder(); 1313 * if(searchCommand.getPriority() != null) { 1314 * whereClause.appendSeparator(" and", " where"); 1315 * whereClause.append(" priority = ?") 1316 * } 1317 * if(searchCommand.getComponent() != null) { 1318 * whereClause.appendSeparator(" and", " where"); 1319 * whereClause.append(" component = ?") 1320 * } 1321 * selectClause.append(whereClause) 1322 * </pre> 1323 * 1324 * @param standard the separator if builder is not empty, null means no separator 1325 * @param defaultIfEmpty the separator if builder is empty, null means no separator 1326 * @return this, to enable chaining 1327 */ 1328 public TextStringBuilder appendSeparator(final String standard, final String defaultIfEmpty) { 1329 final String str = isEmpty() ? defaultIfEmpty : standard; 1330 if (str != null) { 1331 append(str); 1332 } 1333 return this; 1334 } 1335 1336 /** 1337 * Appends current contents of this {@code StrBuilder} to the provided {@link Appendable}. 1338 * <p> 1339 * This method tries to avoid doing any extra copies of contents. 1340 * </p> 1341 * 1342 * @param appendable the appendable to append data to 1343 * @throws IOException if an I/O error occurs. 1344 * 1345 * @see #readFrom(Readable) 1346 */ 1347 public void appendTo(final Appendable appendable) throws IOException { 1348 if (appendable instanceof Writer) { 1349 ((Writer) appendable).write(buffer, 0, size); 1350 } else if (appendable instanceof StringBuilder) { 1351 ((StringBuilder) appendable).append(buffer, 0, size); 1352 } else if (appendable instanceof StringBuffer) { 1353 ((StringBuffer) appendable).append(buffer, 0, size); 1354 } else if (appendable instanceof CharBuffer) { 1355 ((CharBuffer) appendable).put(buffer, 0, size); 1356 } else { 1357 appendable.append(this); 1358 } 1359 } 1360 1361 /** Appends {@code "true"}. */ 1362 private void appendTrue(int index) { 1363 buffer[index++] = 't'; 1364 buffer[index++] = 'r'; 1365 buffer[index++] = 'u'; 1366 buffer[index] = 'e'; 1367 size += TRUE_STRING_SIZE; 1368 } 1369 1370 /** 1371 * Appends an iterable placing separators between each value, but not before the first or after the last. Appending 1372 * a null iterable will have no effect. Each object is appended using {@link #append(Object)}. 1373 * 1374 * @param iterable the iterable to append 1375 * @param separator the separator to use, null means no separator 1376 * @return this, to enable chaining 1377 */ 1378 public TextStringBuilder appendWithSeparators(final Iterable<?> iterable, final String separator) { 1379 if (iterable != null) { 1380 appendWithSeparators(iterable.iterator(), separator); 1381 } 1382 return this; 1383 } 1384 1385 /** 1386 * Appends an iterator placing separators between each value, but not before the first or after the last. Appending 1387 * a null iterator will have no effect. Each object is appended using {@link #append(Object)}. 1388 * 1389 * @param it the iterator to append 1390 * @param separator the separator to use, null means no separator 1391 * @return this, to enable chaining 1392 */ 1393 public TextStringBuilder appendWithSeparators(final Iterator<?> it, final String separator) { 1394 if (it != null) { 1395 final String sep = Objects.toString(separator, StringUtils.EMPTY); 1396 while (it.hasNext()) { 1397 append(it.next()); 1398 if (it.hasNext()) { 1399 append(sep); 1400 } 1401 } 1402 } 1403 return this; 1404 } 1405 1406 /** 1407 * Appends an array placing separators between each value, but not before the first or after the last. Appending a 1408 * null array will have no effect. Each object is appended using {@link #append(Object)}. 1409 * 1410 * @param array the array to append 1411 * @param separator the separator to use, null means no separator 1412 * @return this, to enable chaining 1413 */ 1414 public TextStringBuilder appendWithSeparators(final Object[] array, final String separator) { 1415 if (array != null && array.length > 0) { 1416 final String sep = Objects.toString(separator, StringUtils.EMPTY); 1417 append(array[0]); 1418 for (int i = 1; i < array.length; i++) { 1419 append(sep); 1420 append(array[i]); 1421 } 1422 } 1423 return this; 1424 } 1425 1426 /** 1427 * Gets the contents of this builder as a Reader. 1428 * <p> 1429 * This method allows the contents of the builder to be read using any standard method that expects a Reader. 1430 * </p> 1431 * <p> 1432 * To use, simply create a {@code StrBuilder}, populate it with data, call {@code asReader}, and then read away. 1433 * </p> 1434 * <p> 1435 * The internal character array is shared between the builder and the reader. This allows you to append to the 1436 * builder after creating the reader, and the changes will be picked up. Note however, that no synchronization 1437 * occurs, so you must perform all operations with the builder and the reader in one thread. 1438 * </p> 1439 * <p> 1440 * The returned reader supports marking, and ignores the flush method. 1441 * </p> 1442 * 1443 * @return a reader that reads from this builder 1444 */ 1445 public Reader asReader() { 1446 return new TextStringBuilderReader(); 1447 } 1448 1449 /** 1450 * Creates a tokenizer that can tokenize the contents of this builder. 1451 * <p> 1452 * This method allows the contents of this builder to be tokenized. The tokenizer will be setup by default to 1453 * tokenize on space, tab, newline and form feed (as per StringTokenizer). These values can be changed on the 1454 * tokenizer class, before retrieving the tokens. 1455 * </p> 1456 * <p> 1457 * The returned tokenizer is linked to this builder. You may intermix calls to the builder and tokenizer within 1458 * certain limits, however there is no synchronization. Once the tokenizer has been used once, it must be 1459 * {@link StringTokenizer#reset() reset} to pickup the latest changes in the builder. For example: 1460 * </p> 1461 * 1462 * <pre> 1463 * StrBuilder b = new StrBuilder(); 1464 * b.append("a b "); 1465 * StrTokenizer t = b.asTokenizer(); 1466 * String[] tokens1 = t.getTokenArray(); // returns a,b 1467 * b.append("c d "); 1468 * String[] tokens2 = t.getTokenArray(); // returns a,b (c and d ignored) 1469 * t.reset(); // reset causes builder changes to be picked up 1470 * String[] tokens3 = t.getTokenArray(); // returns a,b,c,d 1471 * </pre> 1472 * 1473 * <p> 1474 * In addition to simply intermixing appends and tokenization, you can also call the set methods on the tokenizer to 1475 * alter how it tokenizes. Just remember to call reset when you want to pickup builder changes. 1476 * </p> 1477 * <p> 1478 * Calling {@link StringTokenizer#reset(String)} or {@link StringTokenizer#reset(char[])} with a non-null value will 1479 * break the link with the builder. 1480 * </p> 1481 * 1482 * @return a tokenizer that is linked to this builder 1483 */ 1484 public StringTokenizer asTokenizer() { 1485 return new TextStringBuilderTokenizer(); 1486 } 1487 1488 /** 1489 * Gets this builder as a Writer that can be written to. 1490 * <p> 1491 * This method allows you to populate the contents of the builder using any standard method that takes a Writer. 1492 * </p> 1493 * <p> 1494 * To use, simply create a {@code StrBuilder}, call {@code asWriter}, and populate away. The data is available at 1495 * any time using the methods of the {@code StrBuilder}. 1496 * </p> 1497 * <p> 1498 * The internal character array is shared between the builder and the writer. This allows you to intermix calls that 1499 * append to the builder and write using the writer and the changes will be occur correctly. Note however, that no 1500 * synchronization occurs, so you must perform all operations with the builder and the writer in one thread. 1501 * </p> 1502 * <p> 1503 * The returned writer ignores the close and flush methods. 1504 * </p> 1505 * 1506 * @return a writer that populates this builder 1507 */ 1508 public Writer asWriter() { 1509 return new TextStringBuilderWriter(); 1510 } 1511 1512 /** 1513 * Implement the {@link Builder} interface. 1514 * 1515 * @return The builder as a String 1516 * @see #toString() 1517 */ 1518 @Override 1519 public String build() { 1520 return toString(); 1521 } 1522 1523 /** 1524 * Gets the current size of the internal character array buffer. 1525 * 1526 * @return The capacity 1527 */ 1528 public int capacity() { 1529 return buffer.length; 1530 } 1531 1532 /** 1533 * Gets the character at the specified index. 1534 * 1535 * @see #setCharAt(int, char) 1536 * @see #deleteCharAt(int) 1537 * @param index the index to retrieve, must be valid 1538 * @return The character at the index 1539 * @throws IndexOutOfBoundsException if the index is invalid 1540 */ 1541 @Override 1542 public char charAt(final int index) { 1543 validateIndex(index); 1544 return buffer[index]; 1545 } 1546 1547 /** 1548 * Clears the string builder (convenience Collections API style method). 1549 * <p> 1550 * This method does not reduce the size of the internal character buffer. To do that, call {@code clear()} followed 1551 * by {@link #minimizeCapacity()}. 1552 * </p> 1553 * <p> 1554 * This method is the same as {@link #setLength(int)} called with zero and is provided to match the API of 1555 * Collections. 1556 * </p> 1557 * 1558 * @return this, to enable chaining 1559 */ 1560 public TextStringBuilder clear() { 1561 size = 0; 1562 return this; 1563 } 1564 1565 /** 1566 * Tests if the string builder contains the specified char. 1567 * 1568 * @param ch the character to find 1569 * @return true if the builder contains the character 1570 */ 1571 public boolean contains(final char ch) { 1572 final char[] thisBuf = buffer; 1573 for (int i = 0; i < this.size; i++) { 1574 if (thisBuf[i] == ch) { 1575 return true; 1576 } 1577 } 1578 return false; 1579 } 1580 1581 /** 1582 * Tests if the string builder contains the specified string. 1583 * 1584 * @param str the string to find 1585 * @return true if the builder contains the string 1586 */ 1587 public boolean contains(final String str) { 1588 return indexOf(str, 0) >= 0; 1589 } 1590 1591 /** 1592 * Tests if the string builder contains a string matched using the specified matcher. 1593 * <p> 1594 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to search for 1595 * the character 'a' followed by a number. 1596 * </p> 1597 * 1598 * @param matcher the matcher to use, null returns -1 1599 * @return true if the matcher finds a match in the builder 1600 */ 1601 public boolean contains(final StringMatcher matcher) { 1602 return indexOf(matcher, 0) >= 0; 1603 } 1604 1605 /** 1606 * Deletes the characters between the two specified indices. 1607 * 1608 * @param startIndex the start index, inclusive, must be valid 1609 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 1610 * @return this, to enable chaining 1611 * @throws IndexOutOfBoundsException if the index is invalid 1612 */ 1613 public TextStringBuilder delete(final int startIndex, final int endIndex) { 1614 final int actualEndIndex = validateRange(startIndex, endIndex); 1615 final int len = actualEndIndex - startIndex; 1616 if (len > 0) { 1617 deleteImpl(startIndex, actualEndIndex, len); 1618 } 1619 return this; 1620 } 1621 1622 /** 1623 * Deletes the character wherever it occurs in the builder. 1624 * 1625 * @param ch the character to delete 1626 * @return this, to enable chaining 1627 */ 1628 public TextStringBuilder deleteAll(final char ch) { 1629 for (int i = 0; i < size; i++) { 1630 if (buffer[i] == ch) { 1631 final int start = i; 1632 while (++i < size) { 1633 if (buffer[i] != ch) { 1634 break; 1635 } 1636 } 1637 final int len = i - start; 1638 deleteImpl(start, i, len); 1639 i -= len; 1640 } 1641 } 1642 return this; 1643 } 1644 1645 /** 1646 * Deletes the string wherever it occurs in the builder. 1647 * 1648 * @param str the string to delete, null causes no action 1649 * @return this, to enable chaining 1650 */ 1651 public TextStringBuilder deleteAll(final String str) { 1652 final int len = str == null ? 0 : str.length(); 1653 if (len > 0) { 1654 int index = indexOf(str, 0); 1655 while (index >= 0) { 1656 deleteImpl(index, index + len, len); 1657 index = indexOf(str, index); 1658 } 1659 } 1660 return this; 1661 } 1662 1663 /** 1664 * Deletes all parts of the builder that the matcher matches. 1665 * <p> 1666 * Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete all 1667 * occurrences where the character 'a' is followed by a number. 1668 * </p> 1669 * 1670 * @param matcher the matcher to use to find the deletion, null causes no action 1671 * @return this, to enable chaining 1672 */ 1673 public TextStringBuilder deleteAll(final StringMatcher matcher) { 1674 return replace(matcher, null, 0, size, -1); 1675 } 1676 1677 /** 1678 * Deletes the character at the specified index. 1679 * 1680 * @see #charAt(int) 1681 * @see #setCharAt(int, char) 1682 * @param index the index to delete 1683 * @return this, to enable chaining 1684 * @throws IndexOutOfBoundsException if the index is invalid 1685 */ 1686 public TextStringBuilder deleteCharAt(final int index) { 1687 validateIndex(index); 1688 deleteImpl(index, index + 1, 1); 1689 return this; 1690 } 1691 1692 /** 1693 * Deletes the character wherever it occurs in the builder. 1694 * 1695 * @param ch the character to delete 1696 * @return this, to enable chaining 1697 */ 1698 public TextStringBuilder deleteFirst(final char ch) { 1699 for (int i = 0; i < size; i++) { 1700 if (buffer[i] == ch) { 1701 deleteImpl(i, i + 1, 1); 1702 break; 1703 } 1704 } 1705 return this; 1706 } 1707 1708 /** 1709 * Deletes the string wherever it occurs in the builder. 1710 * 1711 * @param str the string to delete, null causes no action 1712 * @return this, to enable chaining 1713 */ 1714 public TextStringBuilder deleteFirst(final String str) { 1715 final int len = str == null ? 0 : str.length(); 1716 if (len > 0) { 1717 final int index = indexOf(str, 0); 1718 if (index >= 0) { 1719 deleteImpl(index, index + len, len); 1720 } 1721 } 1722 return this; 1723 } 1724 1725 /** 1726 * Deletes the first match within the builder using the specified matcher. 1727 * <p> 1728 * Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete where 1729 * the character 'a' is followed by a number. 1730 * </p> 1731 * 1732 * @param matcher the matcher to use to find the deletion, null causes no action 1733 * @return this, to enable chaining 1734 */ 1735 public TextStringBuilder deleteFirst(final StringMatcher matcher) { 1736 return replace(matcher, null, 0, size, 1); 1737 } 1738 1739 /** 1740 * Internal method to delete a range without validation. 1741 * 1742 * @param startIndex the start index, must be valid 1743 * @param endIndex the end index (exclusive), must be valid 1744 * @param len the length, must be valid 1745 * @throws IndexOutOfBoundsException if any index is invalid 1746 */ 1747 private void deleteImpl(final int startIndex, final int endIndex, final int len) { 1748 System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex); 1749 size -= len; 1750 } 1751 1752 /** 1753 * Gets the character at the specified index before deleting it. 1754 * 1755 * @see #charAt(int) 1756 * @see #deleteCharAt(int) 1757 * @param index the index to retrieve, must be valid 1758 * @return The character at the index 1759 * @throws IndexOutOfBoundsException if the index is invalid 1760 * @since 1.9 1761 */ 1762 public char drainChar(final int index) { 1763 validateIndex(index); 1764 final char c = buffer[index]; 1765 deleteCharAt(index); 1766 return c; 1767 } 1768 1769 /** 1770 * Drains (copies, then deletes) this character sequence into the specified array. This is equivalent to copying the 1771 * characters from this sequence into the target and then deleting those character from this sequence. 1772 * 1773 * @param startIndex first index to copy, inclusive. 1774 * @param endIndex last index to copy, exclusive. 1775 * @param target the target array, must not be {@code null}. 1776 * @param targetIndex the index to start copying in the target. 1777 * @return How many characters where copied (then deleted). If this builder is empty, return {@code 0}. 1778 * @since 1.9 1779 */ 1780 public int drainChars(final int startIndex, final int endIndex, final char[] target, final int targetIndex) { 1781 final int length = endIndex - startIndex; 1782 if (isEmpty() || length == 0 || target.length == 0) { 1783 return 0; 1784 } 1785 final int actualLen = Math.min(Math.min(size, length), target.length - targetIndex); 1786 getChars(startIndex, actualLen, target, targetIndex); 1787 delete(startIndex, actualLen); 1788 return actualLen; 1789 } 1790 1791 /** 1792 * Checks whether this builder ends with the specified string. 1793 * <p> 1794 * Note that this method handles null input quietly, unlike String. 1795 * </p> 1796 * 1797 * @param str the string to search for, null returns false 1798 * @return true if the builder ends with the string 1799 */ 1800 public boolean endsWith(final String str) { 1801 if (str == null) { 1802 return false; 1803 } 1804 final int len = str.length(); 1805 if (len == 0) { 1806 return true; 1807 } 1808 if (len > size) { 1809 return false; 1810 } 1811 int pos = size - len; 1812 for (int i = 0; i < len; i++, pos++) { 1813 if (buffer[pos] != str.charAt(i)) { 1814 return false; 1815 } 1816 } 1817 return true; 1818 } 1819 1820 /** 1821 * Tests the capacity and ensures that it is at least the size specified. 1822 * 1823 * @param capacity the capacity to ensure 1824 * @return this, to enable chaining 1825 */ 1826 public TextStringBuilder ensureCapacity(final int capacity) { 1827 // checks for overflow 1828 if (capacity > 0 && capacity - buffer.length > 0) { 1829 reallocate(capacity); 1830 } 1831 return this; 1832 } 1833 1834 /** 1835 * Tests the contents of this builder against another to see if they contain the same character content. 1836 * 1837 * @param obj the object to check, null returns false 1838 * @return true if the builders contain the same characters in the same order 1839 */ 1840 @Override 1841 public boolean equals(final Object obj) { 1842 return obj instanceof TextStringBuilder && equals((TextStringBuilder) obj); 1843 } 1844 1845 /** 1846 * Tests the contents of this builder against another to see if they contain the same character content. 1847 * 1848 * @param other the object to check, null returns false 1849 * @return true if the builders contain the same characters in the same order 1850 */ 1851 public boolean equals(final TextStringBuilder other) { 1852 if (this == other) { 1853 return true; 1854 } 1855 if (other == null) { 1856 return false; 1857 } 1858 if (this.size != other.size) { 1859 return false; 1860 } 1861 // Be aware not to use Arrays.equals(buffer, other.buffer) for equals() method 1862 // as length of the buffers may be different (TEXT-211) 1863 final char[] thisBuf = this.buffer; 1864 final char[] otherBuf = other.buffer; 1865 for (int i = size - 1; i >= 0; i--) { 1866 if (thisBuf[i] != otherBuf[i]) { 1867 return false; 1868 } 1869 } 1870 return true; 1871 } 1872 1873 /** 1874 * Tests the contents of this builder against another to see if they contain the same character content ignoring 1875 * case. 1876 * 1877 * @param other the object to check, null returns false 1878 * @return true if the builders contain the same characters in the same order 1879 */ 1880 public boolean equalsIgnoreCase(final TextStringBuilder other) { 1881 if (this == other) { 1882 return true; 1883 } 1884 if (this.size != other.size) { 1885 return false; 1886 } 1887 final char[] thisBuf = this.buffer; 1888 final char[] otherBuf = other.buffer; 1889 for (int i = size - 1; i >= 0; i--) { 1890 final char c1 = thisBuf[i]; 1891 final char c2 = otherBuf[i]; 1892 if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) { 1893 return false; 1894 } 1895 } 1896 return true; 1897 } 1898 1899 /** Gets a direct reference to internal storage, not for public consumption. */ 1900 char[] getBuffer() { 1901 return buffer; 1902 } 1903 1904 /** 1905 * Copies this character array into the specified array. 1906 * 1907 * @param target the target array, null will cause an array to be created 1908 * @return The input array, unless that was null or too small 1909 */ 1910 public char[] getChars(char[] target) { 1911 final int len = length(); 1912 if (target == null || target.length < len) { 1913 target = new char[len]; 1914 } 1915 System.arraycopy(buffer, 0, target, 0, len); 1916 return target; 1917 } 1918 1919 /** 1920 * Copies this character array into the specified array. 1921 * 1922 * @param startIndex first index to copy, inclusive, must be valid. 1923 * @param endIndex last index to copy, exclusive, must be valid. 1924 * @param target the target array, must not be null or too small. 1925 * @param targetIndex the index to start copying in target. 1926 * @throws NullPointerException if the array is null. 1927 * @throws IndexOutOfBoundsException if any index is invalid. 1928 */ 1929 public void getChars(final int startIndex, final int endIndex, final char[] target, final int targetIndex) { 1930 if (startIndex < 0) { 1931 throw new StringIndexOutOfBoundsException(startIndex); 1932 } 1933 if (endIndex < 0 || endIndex > length()) { 1934 throw new StringIndexOutOfBoundsException(endIndex); 1935 } 1936 if (startIndex > endIndex) { 1937 throw new StringIndexOutOfBoundsException("end < start"); 1938 } 1939 System.arraycopy(buffer, startIndex, target, targetIndex, endIndex - startIndex); 1940 } 1941 1942 /** 1943 * Gets the text to be appended when a new line is added. 1944 * 1945 * @return The new line text, null means use system default 1946 */ 1947 public String getNewLineText() { 1948 return newLine; 1949 } 1950 1951 /** 1952 * Gets the text to be appended when null is added. 1953 * 1954 * @return The null text, null means no append 1955 */ 1956 public String getNullText() { 1957 return nullText; 1958 } 1959 1960 /** 1961 * Gets a suitable hash code for this builder. 1962 * 1963 * @return a hash code 1964 */ 1965 @Override 1966 public int hashCode() { 1967 return this.toString().hashCode(); 1968 } 1969 1970 /** 1971 * Searches the string builder to find the first reference to the specified char. 1972 * 1973 * @param ch the character to find 1974 * @return The first index of the character, or -1 if not found 1975 */ 1976 public int indexOf(final char ch) { 1977 return indexOf(ch, 0); 1978 } 1979 1980 /** 1981 * Searches the string builder to find the first reference to the specified char. 1982 * 1983 * @param ch the character to find 1984 * @param startIndex the index to start at, invalid index rounded to edge 1985 * @return The first index of the character, or -1 if not found 1986 */ 1987 public int indexOf(final char ch, int startIndex) { 1988 startIndex = Math.max(0, startIndex); 1989 if (startIndex >= size) { 1990 return StringUtils.INDEX_NOT_FOUND; 1991 } 1992 final char[] thisBuf = buffer; 1993 for (int i = startIndex; i < size; i++) { 1994 if (thisBuf[i] == ch) { 1995 return i; 1996 } 1997 } 1998 return StringUtils.INDEX_NOT_FOUND; 1999 } 2000 2001 /** 2002 * Searches the string builder to find the first reference to the specified string. 2003 * <p> 2004 * Note that a null input string will return -1, whereas the JDK throws an exception. 2005 * </p> 2006 * 2007 * @param str the string to find, null returns -1 2008 * @return The first index of the string, or -1 if not found 2009 */ 2010 public int indexOf(final String str) { 2011 return indexOf(str, 0); 2012 } 2013 2014 /** 2015 * Searches the string builder to find the first reference to the specified string starting searching from the given 2016 * index. 2017 * <p> 2018 * Note that a null input string will return -1, whereas the JDK throws an exception. 2019 * </p> 2020 * 2021 * @param str the string to find, null returns -1 2022 * @param startIndex the index to start at, invalid index rounded to edge 2023 * @return The first index of the string, or -1 if not found 2024 */ 2025 public int indexOf(final String str, int startIndex) { 2026 startIndex = Math.max(0, startIndex); 2027 if (str == null || startIndex >= size) { 2028 return StringUtils.INDEX_NOT_FOUND; 2029 } 2030 final int strLen = str.length(); 2031 if (strLen == 1) { 2032 return indexOf(str.charAt(0), startIndex); 2033 } 2034 if (strLen == 0) { 2035 return startIndex; 2036 } 2037 if (strLen > size) { 2038 return StringUtils.INDEX_NOT_FOUND; 2039 } 2040 final char[] thisBuf = buffer; 2041 final int len = size - strLen + 1; 2042 outer: for (int i = startIndex; i < len; i++) { 2043 for (int j = 0; j < strLen; j++) { 2044 if (str.charAt(j) != thisBuf[i + j]) { 2045 continue outer; 2046 } 2047 } 2048 return i; 2049 } 2050 return StringUtils.INDEX_NOT_FOUND; 2051 } 2052 2053 /** 2054 * Searches the string builder using the matcher to find the first match. 2055 * <p> 2056 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the 2057 * character 'a' followed by a number. 2058 * </p> 2059 * 2060 * @param matcher the matcher to use, null returns -1 2061 * @return The first index matched, or -1 if not found 2062 */ 2063 public int indexOf(final StringMatcher matcher) { 2064 return indexOf(matcher, 0); 2065 } 2066 2067 /** 2068 * Searches the string builder using the matcher to find the first match searching from the given index. 2069 * <p> 2070 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the 2071 * character 'a' followed by a number. 2072 * </p> 2073 * 2074 * @param matcher the matcher to use, null returns -1 2075 * @param startIndex the index to start at, invalid index rounded to edge 2076 * @return The first index matched, or -1 if not found 2077 */ 2078 public int indexOf(final StringMatcher matcher, int startIndex) { 2079 startIndex = Math.max(0, startIndex); 2080 if (matcher == null || startIndex >= size) { 2081 return StringUtils.INDEX_NOT_FOUND; 2082 } 2083 final int len = size; 2084 final char[] buf = buffer; 2085 for (int i = startIndex; i < len; i++) { 2086 if (matcher.isMatch(buf, i, startIndex, len) > 0) { 2087 return i; 2088 } 2089 } 2090 return StringUtils.INDEX_NOT_FOUND; 2091 } 2092 2093 /** 2094 * Inserts the value into this builder. 2095 * 2096 * @param index the index to add at, must be valid 2097 * @param value the value to insert 2098 * @return this, to enable chaining 2099 * @throws IndexOutOfBoundsException if the index is invalid 2100 */ 2101 public TextStringBuilder insert(final int index, final boolean value) { 2102 validateIndex(index); 2103 if (value) { 2104 ensureCapacity(size + TRUE_STRING_SIZE); 2105 System.arraycopy(buffer, index, buffer, index + TRUE_STRING_SIZE, size - index); 2106 appendTrue(index); 2107 } else { 2108 ensureCapacity(size + FALSE_STRING_SIZE); 2109 System.arraycopy(buffer, index, buffer, index + FALSE_STRING_SIZE, size - index); 2110 appendFalse(index); 2111 } 2112 return this; 2113 } 2114 2115 /** 2116 * Inserts the value into this builder. 2117 * 2118 * @param index the index to add at, must be valid 2119 * @param value the value to insert 2120 * @return this, to enable chaining 2121 * @throws IndexOutOfBoundsException if the index is invalid 2122 */ 2123 public TextStringBuilder insert(final int index, final char value) { 2124 validateIndex(index); 2125 ensureCapacity(size + 1); 2126 System.arraycopy(buffer, index, buffer, index + 1, size - index); 2127 buffer[index] = value; 2128 size++; 2129 return this; 2130 } 2131 2132 /** 2133 * Inserts the character array into this builder. Inserting null will use the stored null text value. 2134 * 2135 * @param index the index to add at, must be valid 2136 * @param chars the char array to insert 2137 * @return this, to enable chaining 2138 * @throws IndexOutOfBoundsException if the index is invalid 2139 */ 2140 public TextStringBuilder insert(final int index, final char[] chars) { 2141 validateIndex(index); 2142 if (chars == null) { 2143 return insert(index, nullText); 2144 } 2145 final int len = chars.length; 2146 if (len > 0) { 2147 ensureCapacity(size + len); 2148 System.arraycopy(buffer, index, buffer, index + len, size - index); 2149 System.arraycopy(chars, 0, buffer, index, len); 2150 size += len; 2151 } 2152 return this; 2153 } 2154 2155 /** 2156 * Inserts part of the character array into this builder. Inserting null will use the stored null text value. 2157 * 2158 * @param index the index to add at, must be valid 2159 * @param chars the char array to insert 2160 * @param offset the offset into the character array to start at, must be valid 2161 * @param length the length of the character array part to copy, must be positive 2162 * @return this, to enable chaining 2163 * @throws IndexOutOfBoundsException if any index is invalid 2164 */ 2165 public TextStringBuilder insert(final int index, final char[] chars, final int offset, final int length) { 2166 validateIndex(index); 2167 if (chars == null) { 2168 return insert(index, nullText); 2169 } 2170 if (offset < 0 || offset > chars.length) { 2171 throw new StringIndexOutOfBoundsException("Invalid offset: " + offset); 2172 } 2173 if (length < 0 || offset + length > chars.length) { 2174 throw new StringIndexOutOfBoundsException("Invalid length: " + length); 2175 } 2176 if (length > 0) { 2177 ensureCapacity(size + length); 2178 System.arraycopy(buffer, index, buffer, index + length, size - index); 2179 System.arraycopy(chars, offset, buffer, index, length); 2180 size += length; 2181 } 2182 return this; 2183 } 2184 2185 /** 2186 * Inserts the value into this builder. 2187 * 2188 * @param index the index to add at, must be valid 2189 * @param value the value to insert 2190 * @return this, to enable chaining 2191 * @throws IndexOutOfBoundsException if the index is invalid 2192 */ 2193 public TextStringBuilder insert(final int index, final double value) { 2194 return insert(index, String.valueOf(value)); 2195 } 2196 2197 /** 2198 * Inserts the value into this builder. 2199 * 2200 * @param index the index to add at, must be valid 2201 * @param value the value to insert 2202 * @return this, to enable chaining 2203 * @throws IndexOutOfBoundsException if the index is invalid 2204 */ 2205 public TextStringBuilder insert(final int index, final float value) { 2206 return insert(index, String.valueOf(value)); 2207 } 2208 2209 /** 2210 * Inserts the value into this builder. 2211 * 2212 * @param index the index to add at, must be valid 2213 * @param value the value to insert 2214 * @return this, to enable chaining 2215 * @throws IndexOutOfBoundsException if the index is invalid 2216 */ 2217 public TextStringBuilder insert(final int index, final int value) { 2218 return insert(index, String.valueOf(value)); 2219 } 2220 2221 /** 2222 * Inserts the value into this builder. 2223 * 2224 * @param index the index to add at, must be valid 2225 * @param value the value to insert 2226 * @return this, to enable chaining 2227 * @throws IndexOutOfBoundsException if the index is invalid 2228 */ 2229 public TextStringBuilder insert(final int index, final long value) { 2230 return insert(index, String.valueOf(value)); 2231 } 2232 2233 /** 2234 * Inserts the string representation of an object into this builder. Inserting null will use the stored null text 2235 * value. 2236 * 2237 * @param index the index to add at, must be valid 2238 * @param obj the object to insert 2239 * @return this, to enable chaining 2240 * @throws IndexOutOfBoundsException if the index is invalid 2241 */ 2242 public TextStringBuilder insert(final int index, final Object obj) { 2243 if (obj == null) { 2244 return insert(index, nullText); 2245 } 2246 return insert(index, obj.toString()); 2247 } 2248 2249 /** 2250 * Inserts the string into this builder. Inserting null will use the stored null text value. 2251 * 2252 * @param index the index to add at, must be valid 2253 * @param str the string to insert 2254 * @return this, to enable chaining 2255 * @throws IndexOutOfBoundsException if the index is invalid 2256 */ 2257 public TextStringBuilder insert(final int index, String str) { 2258 validateIndex(index); 2259 if (str == null) { 2260 str = nullText; 2261 } 2262 if (str != null) { 2263 final int strLen = str.length(); 2264 if (strLen > 0) { 2265 final int newSize = size + strLen; 2266 ensureCapacity(newSize); 2267 System.arraycopy(buffer, index, buffer, index + strLen, size - index); 2268 size = newSize; 2269 str.getChars(0, strLen, buffer, index); 2270 } 2271 } 2272 return this; 2273 } 2274 2275 /** 2276 * Checks is the string builder is empty (convenience Collections API style method). 2277 * <p> 2278 * This method is the same as checking {@link #length()} and is provided to match the API of Collections. 2279 * </p> 2280 * 2281 * @return {@code true} if the size is {@code 0}. 2282 */ 2283 public boolean isEmpty() { 2284 return size == 0; 2285 } 2286 2287 /** 2288 * Checks is the string builder is not empty. 2289 * <p> 2290 * This method is the same as checking {@link #length()}. 2291 * </p> 2292 * 2293 * @return {@code true} if the size is not {@code 0}. 2294 * @since 1.9 2295 */ 2296 public boolean isNotEmpty() { 2297 return size != 0; 2298 } 2299 2300 /** 2301 * Gets whether the internal buffer has been reallocated. 2302 * 2303 * @return Whether the internal buffer has been reallocated. 2304 * @since 1.9 2305 */ 2306 public boolean isReallocated() { 2307 return reallocations > 0; 2308 } 2309 2310 /** 2311 * Searches the string builder to find the last reference to the specified char. 2312 * 2313 * @param ch the character to find 2314 * @return The last index of the character, or -1 if not found 2315 */ 2316 public int lastIndexOf(final char ch) { 2317 return lastIndexOf(ch, size - 1); 2318 } 2319 2320 /** 2321 * Searches the string builder to find the last reference to the specified char. 2322 * 2323 * @param ch the character to find 2324 * @param startIndex the index to start at, invalid index rounded to edge 2325 * @return The last index of the character, or -1 if not found 2326 */ 2327 public int lastIndexOf(final char ch, int startIndex) { 2328 startIndex = startIndex >= size ? size - 1 : startIndex; 2329 if (startIndex < 0) { 2330 return StringUtils.INDEX_NOT_FOUND; 2331 } 2332 for (int i = startIndex; i >= 0; i--) { 2333 if (buffer[i] == ch) { 2334 return i; 2335 } 2336 } 2337 return StringUtils.INDEX_NOT_FOUND; 2338 } 2339 2340 /** 2341 * Searches the string builder to find the last reference to the specified string. 2342 * <p> 2343 * Note that a null input string will return -1, whereas the JDK throws an exception. 2344 * </p> 2345 * 2346 * @param str the string to find, null returns -1 2347 * @return The last index of the string, or -1 if not found 2348 */ 2349 public int lastIndexOf(final String str) { 2350 return lastIndexOf(str, size - 1); 2351 } 2352 2353 /** 2354 * Searches the string builder to find the last reference to the specified string starting searching from the given 2355 * index. 2356 * <p> 2357 * Note that a null input string will return -1, whereas the JDK throws an exception. 2358 * </p> 2359 * 2360 * @param str the string to find, null returns -1 2361 * @param startIndex the index to start at, invalid index rounded to edge 2362 * @return The last index of the string, or -1 if not found 2363 */ 2364 public int lastIndexOf(final String str, int startIndex) { 2365 startIndex = startIndex >= size ? size - 1 : startIndex; 2366 if (str == null || startIndex < 0) { 2367 return StringUtils.INDEX_NOT_FOUND; 2368 } 2369 final int strLen = str.length(); 2370 if (strLen > 0 && strLen <= size) { 2371 if (strLen == 1) { 2372 return lastIndexOf(str.charAt(0), startIndex); 2373 } 2374 2375 outer: for (int i = startIndex - strLen + 1; i >= 0; i--) { 2376 for (int j = 0; j < strLen; j++) { 2377 if (str.charAt(j) != buffer[i + j]) { 2378 continue outer; 2379 } 2380 } 2381 return i; 2382 } 2383 2384 } else if (strLen == 0) { 2385 return startIndex; 2386 } 2387 return StringUtils.INDEX_NOT_FOUND; 2388 } 2389 2390 /** 2391 * Searches the string builder using the matcher to find the last match. 2392 * <p> 2393 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the 2394 * character 'a' followed by a number. 2395 * </p> 2396 * 2397 * @param matcher the matcher to use, null returns -1 2398 * @return The last index matched, or -1 if not found 2399 */ 2400 public int lastIndexOf(final StringMatcher matcher) { 2401 return lastIndexOf(matcher, size); 2402 } 2403 2404 /** 2405 * Searches the string builder using the matcher to find the last match searching from the given index. 2406 * <p> 2407 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the 2408 * character 'a' followed by a number. 2409 * </p> 2410 * 2411 * @param matcher the matcher to use, null returns -1 2412 * @param startIndex the index to start at, invalid index rounded to edge 2413 * @return The last index matched, or -1 if not found 2414 */ 2415 public int lastIndexOf(final StringMatcher matcher, int startIndex) { 2416 startIndex = startIndex >= size ? size - 1 : startIndex; 2417 if (matcher == null || startIndex < 0) { 2418 return StringUtils.INDEX_NOT_FOUND; 2419 } 2420 final char[] buf = buffer; 2421 final int endIndex = startIndex + 1; 2422 for (int i = startIndex; i >= 0; i--) { 2423 if (matcher.isMatch(buf, i, 0, endIndex) > 0) { 2424 return i; 2425 } 2426 } 2427 return StringUtils.INDEX_NOT_FOUND; 2428 } 2429 2430 /** 2431 * Extracts the leftmost characters from the string builder without throwing an exception. 2432 * <p> 2433 * This method extracts the left {@code length} characters from the builder. If this many characters are not 2434 * available, the whole builder is returned. Thus the returned string may be shorter than the length requested. 2435 * </p> 2436 * 2437 * @param length the number of characters to extract, negative returns empty string 2438 * @return The new string 2439 */ 2440 public String leftString(final int length) { 2441 if (length <= 0) { 2442 return StringUtils.EMPTY; 2443 } 2444 if (length >= size) { 2445 return new String(buffer, 0, size); 2446 } 2447 return new String(buffer, 0, length); 2448 } 2449 2450 /** 2451 * Gets the length of the string builder. 2452 * 2453 * @return The length 2454 */ 2455 @Override 2456 public int length() { 2457 return size; 2458 } 2459 2460 /** 2461 * Extracts some characters from the middle of the string builder without throwing an exception. 2462 * <p> 2463 * This method extracts {@code length} characters from the builder at the specified index. If the index is negative 2464 * it is treated as zero. If the index is greater than the builder size, it is treated as the builder size. If the 2465 * length is negative, the empty string is returned. If insufficient characters are available in the builder, as 2466 * much as possible is returned. Thus the returned string may be shorter than the length requested. 2467 * </p> 2468 * 2469 * @param index the index to start at, negative means zero 2470 * @param length the number of characters to extract, negative returns empty string 2471 * @return The new string 2472 */ 2473 public String midString(int index, final int length) { 2474 if (index < 0) { 2475 index = 0; 2476 } 2477 if (length <= 0 || index >= size) { 2478 return StringUtils.EMPTY; 2479 } 2480 if (size <= index + length) { 2481 return new String(buffer, index, size - index); 2482 } 2483 return new String(buffer, index, length); 2484 } 2485 2486 /** 2487 * Minimizes the capacity to the actual length of the string. 2488 * 2489 * @return this, to enable chaining 2490 */ 2491 public TextStringBuilder minimizeCapacity() { 2492 if (buffer.length > size) { 2493 reallocate(size); 2494 } 2495 return this; 2496 } 2497 2498 /** 2499 * If possible, reads chars from the provided {@link CharBuffer} directly into underlying character buffer without 2500 * making extra copies. 2501 * 2502 * @param charBuffer CharBuffer to read. 2503 * @return The number of characters read. 2504 * 2505 * @see #appendTo(Appendable) 2506 * @since 1.9 2507 */ 2508 public int readFrom(final CharBuffer charBuffer) { 2509 final int oldSize = size; 2510 final int remaining = charBuffer.remaining(); 2511 ensureCapacity(size + remaining); 2512 charBuffer.get(buffer, size, remaining); 2513 size += remaining; 2514 return size - oldSize; 2515 } 2516 2517 /** 2518 * If possible, reads all chars from the provided {@link Readable} directly into underlying character buffer without 2519 * making extra copies. 2520 * 2521 * @param readable object to read from 2522 * @return The number of characters read 2523 * @throws IOException if an I/O error occurs. 2524 * 2525 * @see #appendTo(Appendable) 2526 */ 2527 public int readFrom(final Readable readable) throws IOException { 2528 if (readable instanceof Reader) { 2529 return readFrom((Reader) readable); 2530 } 2531 if (readable instanceof CharBuffer) { 2532 return readFrom((CharBuffer) readable); 2533 } 2534 final int oldSize = size; 2535 while (true) { 2536 ensureCapacity(size + 1); 2537 final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size); 2538 final int read = readable.read(buf); 2539 if (read == EOS) { 2540 break; 2541 } 2542 size += read; 2543 } 2544 return size - oldSize; 2545 } 2546 2547 /** 2548 * If possible, reads all chars from the provided {@link Reader} directly into underlying character buffer without 2549 * making extra copies. 2550 * 2551 * @param reader Reader to read. 2552 * @return The number of characters read or -1 if we reached the end of stream. 2553 * @throws IOException if an I/O error occurs. 2554 * 2555 * @see #appendTo(Appendable) 2556 * @since 1.9 2557 */ 2558 public int readFrom(final Reader reader) throws IOException { 2559 final int oldSize = size; 2560 ensureCapacity(size + 1); 2561 int readCount = reader.read(buffer, size, buffer.length - size); 2562 if (readCount == EOS) { 2563 return EOS; 2564 } 2565 do { 2566 size += readCount; 2567 ensureCapacity(size + 1); 2568 readCount = reader.read(buffer, size, buffer.length - size); 2569 } while (readCount != EOS); 2570 return size - oldSize; 2571 } 2572 2573 /** 2574 * If possible, reads {@code count} chars from the provided {@link Reader} directly into underlying character buffer 2575 * without making extra copies. 2576 * 2577 * @param reader Reader to read. 2578 * @param count The maximum characters to read, a value <= 0 returns 0. 2579 * @return The number of characters read. If less than {@code count}, then we've reached the end-of-stream, or -1 if 2580 * we reached the end of stream. 2581 * @throws IOException if an I/O error occurs. 2582 * @see #appendTo(Appendable) 2583 * @since 1.9 2584 */ 2585 public int readFrom(final Reader reader, final int count) throws IOException { 2586 if (count <= 0) { 2587 return 0; 2588 } 2589 final int oldSize = size; 2590 ensureCapacity(size + count); 2591 int target = count; 2592 int readCount = reader.read(buffer, size, target); 2593 if (readCount == EOS) { 2594 return EOS; 2595 } 2596 do { 2597 target -= readCount; 2598 size += readCount; 2599 readCount = reader.read(buffer, size, target); 2600 } while (target > 0 && readCount != EOS); 2601 return size - oldSize; 2602 } 2603 2604 /** 2605 * Reallocates the buffer to the new length. 2606 * 2607 * @param newLength the length of the copy to be returned 2608 */ 2609 private void reallocate(final int newLength) { 2610 this.buffer = Arrays.copyOf(buffer, newLength); 2611 this.reallocations++; 2612 } 2613 2614 /** 2615 * Replaces a portion of the string builder with another string. The length of the inserted string does not have to 2616 * match the removed length. 2617 * 2618 * @param startIndex the start index, inclusive, must be valid 2619 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 2620 * @param replaceStr the string to replace with, null means delete range 2621 * @return this, to enable chaining 2622 * @throws IndexOutOfBoundsException if the index is invalid 2623 */ 2624 public TextStringBuilder replace(final int startIndex, int endIndex, final String replaceStr) { 2625 endIndex = validateRange(startIndex, endIndex); 2626 final int insertLen = replaceStr == null ? 0 : replaceStr.length(); 2627 replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen); 2628 return this; 2629 } 2630 2631 /** 2632 * Advanced search and replaces within the builder using a matcher. 2633 * <p> 2634 * Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all 2635 * occurrences where the character 'a' is followed by a number. 2636 * </p> 2637 * 2638 * @param matcher the matcher to use to find the deletion, null causes no action 2639 * @param replaceStr the string to replace the match with, null is a delete 2640 * @param startIndex the start index, inclusive, must be valid 2641 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 2642 * @param replaceCount the number of times to replace, -1 for replace all 2643 * @return this, to enable chaining 2644 * @throws IndexOutOfBoundsException if start index is invalid 2645 */ 2646 public TextStringBuilder replace(final StringMatcher matcher, final String replaceStr, final int startIndex, 2647 int endIndex, final int replaceCount) { 2648 endIndex = validateRange(startIndex, endIndex); 2649 return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount); 2650 } 2651 2652 /** 2653 * Replaces the search character with the replace character throughout the builder. 2654 * 2655 * @param search the search character 2656 * @param replace the replace character 2657 * @return this, to enable chaining 2658 */ 2659 public TextStringBuilder replaceAll(final char search, final char replace) { 2660 if (search != replace) { 2661 for (int i = 0; i < size; i++) { 2662 if (buffer[i] == search) { 2663 buffer[i] = replace; 2664 } 2665 } 2666 } 2667 return this; 2668 } 2669 2670 /** 2671 * Replaces the search string with the replace string throughout the builder. 2672 * 2673 * @param searchStr the search string, null causes no action to occur 2674 * @param replaceStr the replace string, null is equivalent to an empty string 2675 * @return this, to enable chaining 2676 */ 2677 public TextStringBuilder replaceAll(final String searchStr, final String replaceStr) { 2678 final int searchLen = searchStr == null ? 0 : searchStr.length(); 2679 if (searchLen > 0) { 2680 final int replaceLen = replaceStr == null ? 0 : replaceStr.length(); 2681 int index = indexOf(searchStr, 0); 2682 while (index >= 0) { 2683 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); 2684 index = indexOf(searchStr, index + replaceLen); 2685 } 2686 } 2687 return this; 2688 } 2689 2690 /** 2691 * Replaces all matches within the builder with the replace string. 2692 * <p> 2693 * Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace all 2694 * occurrences where the character 'a' is followed by a number. 2695 * </p> 2696 * 2697 * @param matcher the matcher to use to find the deletion, null causes no action 2698 * @param replaceStr the replace string, null is equivalent to an empty string 2699 * @return this, to enable chaining 2700 */ 2701 public TextStringBuilder replaceAll(final StringMatcher matcher, final String replaceStr) { 2702 return replace(matcher, replaceStr, 0, size, -1); 2703 } 2704 2705 /** 2706 * Replaces the first instance of the search character with the replace character in the builder. 2707 * 2708 * @param search the search character 2709 * @param replace the replace character 2710 * @return this, to enable chaining 2711 */ 2712 public TextStringBuilder replaceFirst(final char search, final char replace) { 2713 if (search != replace) { 2714 for (int i = 0; i < size; i++) { 2715 if (buffer[i] == search) { 2716 buffer[i] = replace; 2717 break; 2718 } 2719 } 2720 } 2721 return this; 2722 } 2723 2724 /** 2725 * Replaces the first instance of the search string with the replace string. 2726 * 2727 * @param searchStr the search string, null causes no action to occur 2728 * @param replaceStr the replace string, null is equivalent to an empty string 2729 * @return this, to enable chaining 2730 */ 2731 public TextStringBuilder replaceFirst(final String searchStr, final String replaceStr) { 2732 final int searchLen = searchStr == null ? 0 : searchStr.length(); 2733 if (searchLen > 0) { 2734 final int index = indexOf(searchStr, 0); 2735 if (index >= 0) { 2736 final int replaceLen = replaceStr == null ? 0 : replaceStr.length(); 2737 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); 2738 } 2739 } 2740 return this; 2741 } 2742 2743 /** 2744 * Replaces the first match within the builder with the replace string. 2745 * <p> 2746 * Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace where 2747 * the character 'a' is followed by a number. 2748 * </p> 2749 * 2750 * @param matcher the matcher to use to find the deletion, null causes no action 2751 * @param replaceStr the replace string, null is equivalent to an empty string 2752 * @return this, to enable chaining 2753 */ 2754 public TextStringBuilder replaceFirst(final StringMatcher matcher, final String replaceStr) { 2755 return replace(matcher, replaceStr, 0, size, 1); 2756 } 2757 2758 /** 2759 * Internal method to delete a range without validation. 2760 * 2761 * @param startIndex the start index, must be valid 2762 * @param endIndex the end index (exclusive), must be valid 2763 * @param removeLen the length to remove (endIndex - startIndex), must be valid 2764 * @param insertStr the string to replace with, null means delete range 2765 * @param insertLen the length of the insert string, must be valid 2766 * @throws IndexOutOfBoundsException if any index is invalid 2767 */ 2768 private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr, 2769 final int insertLen) { 2770 final int newSize = size - removeLen + insertLen; 2771 if (insertLen != removeLen) { 2772 ensureCapacity(newSize); 2773 System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex); 2774 size = newSize; 2775 } 2776 if (insertLen > 0) { 2777 insertStr.getChars(0, insertLen, buffer, startIndex); 2778 } 2779 } 2780 2781 /** 2782 * Replaces within the builder using a matcher. 2783 * <p> 2784 * Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all 2785 * occurrences where the character 'a' is followed by a number. 2786 * </p> 2787 * 2788 * @param matcher the matcher to use to find the deletion, null causes no action 2789 * @param replaceStr the string to replace the match with, null is a delete 2790 * @param from the start index, must be valid 2791 * @param to the end index (exclusive), must be valid 2792 * @param replaceCount the number of times to replace, -1 for replace all 2793 * @return this, to enable chaining 2794 * @throws IndexOutOfBoundsException if any index is invalid 2795 */ 2796 private TextStringBuilder replaceImpl(final StringMatcher matcher, final String replaceStr, final int from, int to, 2797 int replaceCount) { 2798 if (matcher == null || size == 0) { 2799 return this; 2800 } 2801 final int replaceLen = replaceStr == null ? 0 : replaceStr.length(); 2802 for (int i = from; i < to && replaceCount != 0; i++) { 2803 final char[] buf = buffer; 2804 final int removeLen = matcher.isMatch(buf, i, from, to); 2805 if (removeLen > 0) { 2806 replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen); 2807 to = to - removeLen + replaceLen; 2808 i = i + replaceLen - 1; 2809 if (replaceCount > 0) { 2810 replaceCount--; 2811 } 2812 } 2813 } 2814 return this; 2815 } 2816 2817 /** 2818 * Reverses the string builder placing each character in the opposite index. 2819 * 2820 * @return this, to enable chaining 2821 */ 2822 public TextStringBuilder reverse() { 2823 if (size == 0) { 2824 return this; 2825 } 2826 2827 final int half = size / 2; 2828 final char[] buf = buffer; 2829 for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++, rightIdx--) { 2830 final char swap = buf[leftIdx]; 2831 buf[leftIdx] = buf[rightIdx]; 2832 buf[rightIdx] = swap; 2833 } 2834 return this; 2835 } 2836 2837 /** 2838 * Extracts the rightmost characters from the string builder without throwing an exception. 2839 * <p> 2840 * This method extracts the right {@code length} characters from the builder. If this many characters are not 2841 * available, the whole builder is returned. Thus the returned string may be shorter than the length requested. 2842 * </p> 2843 * 2844 * @param length the number of characters to extract, negative returns empty string 2845 * @return The new string 2846 */ 2847 public String rightString(final int length) { 2848 if (length <= 0) { 2849 return StringUtils.EMPTY; 2850 } 2851 if (length >= size) { 2852 return new String(buffer, 0, size); 2853 } 2854 return new String(buffer, size - length, length); 2855 } 2856 2857 /** 2858 * Clears and sets this builder to the given value. 2859 * 2860 * @see #charAt(int) 2861 * @see #deleteCharAt(int) 2862 * @param str the new value. 2863 * @return this, to enable chaining 2864 * @since 1.9 2865 */ 2866 public TextStringBuilder set(final CharSequence str) { 2867 clear(); 2868 append(str); 2869 return this; 2870 } 2871 2872 /** 2873 * Sets the character at the specified index. 2874 * 2875 * @see #charAt(int) 2876 * @see #deleteCharAt(int) 2877 * @param index the index to set 2878 * @param ch the new character 2879 * @return this, to enable chaining 2880 * @throws IndexOutOfBoundsException if the index is invalid 2881 */ 2882 public TextStringBuilder setCharAt(final int index, final char ch) { 2883 validateIndex(index); 2884 buffer[index] = ch; 2885 return this; 2886 } 2887 2888 /** 2889 * Updates the length of the builder by either dropping the last characters or adding filler of Unicode zero. 2890 * 2891 * @param length the length to set to, must be zero or positive 2892 * @return this, to enable chaining 2893 * @throws IndexOutOfBoundsException if the length is negative 2894 */ 2895 public TextStringBuilder setLength(final int length) { 2896 if (length < 0) { 2897 throw new StringIndexOutOfBoundsException(length); 2898 } 2899 if (length < size) { 2900 size = length; 2901 } else if (length > size) { 2902 ensureCapacity(length); 2903 final int oldEnd = size; 2904 size = length; 2905 Arrays.fill(buffer, oldEnd, length, '\0'); 2906 } 2907 return this; 2908 } 2909 2910 /** 2911 * Sets the text to be appended when a new line is added. 2912 * 2913 * @param newLine the new line text, null means use system default 2914 * @return this, to enable chaining 2915 */ 2916 public TextStringBuilder setNewLineText(final String newLine) { 2917 this.newLine = newLine; 2918 return this; 2919 } 2920 2921 /** 2922 * Sets the text to be appended when null is added. 2923 * 2924 * @param nullText the null text, null means no append 2925 * @return this, to enable chaining 2926 */ 2927 public TextStringBuilder setNullText(String nullText) { 2928 if (nullText != null && nullText.isEmpty()) { 2929 nullText = null; 2930 } 2931 this.nullText = nullText; 2932 return this; 2933 } 2934 2935 /** 2936 * Gets the length of the string builder. 2937 * <p> 2938 * This method is the same as {@link #length()} and is provided to match the API of Collections. 2939 * </p> 2940 * 2941 * @return The length 2942 */ 2943 public int size() { 2944 return size; 2945 } 2946 2947 /** 2948 * Checks whether this builder starts with the specified string. 2949 * <p> 2950 * Note that this method handles null input quietly, unlike String. 2951 * </p> 2952 * 2953 * @param str the string to search for, null returns false 2954 * @return true if the builder starts with the string 2955 */ 2956 public boolean startsWith(final String str) { 2957 if (str == null) { 2958 return false; 2959 } 2960 final int len = str.length(); 2961 if (len == 0) { 2962 return true; 2963 } 2964 if (len > size) { 2965 return false; 2966 } 2967 for (int i = 0; i < len; i++) { 2968 if (buffer[i] != str.charAt(i)) { 2969 return false; 2970 } 2971 } 2972 return true; 2973 } 2974 2975 /** 2976 * {@inheritDoc} 2977 */ 2978 @Override 2979 public CharSequence subSequence(final int startIndex, final int endIndex) { 2980 if (startIndex < 0) { 2981 throw new StringIndexOutOfBoundsException(startIndex); 2982 } 2983 if (endIndex > size) { 2984 throw new StringIndexOutOfBoundsException(endIndex); 2985 } 2986 if (startIndex > endIndex) { 2987 throw new StringIndexOutOfBoundsException(endIndex - startIndex); 2988 } 2989 return substring(startIndex, endIndex); 2990 } 2991 2992 /** 2993 * Extracts a portion of this string builder as a string. 2994 * 2995 * @param start the start index, inclusive, must be valid 2996 * @return The new string 2997 * @throws IndexOutOfBoundsException if the index is invalid 2998 */ 2999 public String substring(final int start) { 3000 return substring(start, size); 3001 } 3002 3003 /** 3004 * Extracts a portion of this string builder as a string. 3005 * <p> 3006 * Note: This method treats an endIndex greater than the length of the builder as equal to the length of the 3007 * builder, and continues without error, unlike StringBuffer or String. 3008 * </p> 3009 * 3010 * @param startIndex the start index, inclusive, must be valid 3011 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 3012 * @return The new string 3013 * @throws IndexOutOfBoundsException if the index is invalid 3014 */ 3015 public String substring(final int startIndex, int endIndex) { 3016 endIndex = validateRange(startIndex, endIndex); 3017 return new String(buffer, startIndex, endIndex - startIndex); 3018 } 3019 3020 /** 3021 * Copies the builder's character array into a new character array. 3022 * 3023 * @return a new array that represents the contents of the builder 3024 */ 3025 public char[] toCharArray() { 3026 return size == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOf(buffer, size); 3027 } 3028 3029 /** 3030 * Copies part of the builder's character array into a new character array. 3031 * 3032 * @param startIndex the start index, inclusive, must be valid 3033 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 3034 * @return a new array that holds part of the contents of the builder 3035 * @throws IndexOutOfBoundsException if startIndex is invalid, or if endIndex is invalid (but endIndex greater than 3036 * size is valid) 3037 */ 3038 public char[] toCharArray(final int startIndex, int endIndex) { 3039 endIndex = validateRange(startIndex, endIndex); 3040 final int len = endIndex - startIndex; 3041 return len == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOfRange(buffer, startIndex, endIndex); 3042 } 3043 3044 /** 3045 * Gets a String version of the string builder, creating a new instance each time the method is called. 3046 * <p> 3047 * Note that unlike StringBuffer, the string version returned is independent of the string builder. 3048 * </p> 3049 * 3050 * @return The builder as a String 3051 */ 3052 @Override 3053 public String toString() { 3054 return new String(buffer, 0, size); 3055 } 3056 3057 /** 3058 * Gets a StringBuffer version of the string builder, creating a new instance each time the method is called. 3059 * 3060 * @return The builder as a StringBuffer 3061 */ 3062 public StringBuffer toStringBuffer() { 3063 return new StringBuffer(size).append(buffer, 0, size); 3064 } 3065 3066 /** 3067 * Gets a StringBuilder version of the string builder, creating a new instance each time the method is called. 3068 * 3069 * @return The builder as a StringBuilder 3070 */ 3071 public StringBuilder toStringBuilder() { 3072 return new StringBuilder(size).append(buffer, 0, size); 3073 } 3074 3075 /** 3076 * Trims the builder by removing characters less than or equal to a space from the beginning and end. 3077 * 3078 * @return this, to enable chaining 3079 */ 3080 public TextStringBuilder trim() { 3081 if (size == 0) { 3082 return this; 3083 } 3084 int len = size; 3085 final char[] buf = buffer; 3086 int pos = 0; 3087 while (pos < len && buf[pos] <= SPACE) { 3088 pos++; 3089 } 3090 while (pos < len && buf[len - 1] <= SPACE) { 3091 len--; 3092 } 3093 if (len < size) { 3094 delete(len, size); 3095 } 3096 if (pos > 0) { 3097 delete(0, pos); 3098 } 3099 return this; 3100 } 3101 3102 /** 3103 * Validates that an index is in the range {@code 0 <= index <= size}. 3104 * 3105 * @param index the index to test. 3106 * @throws IndexOutOfBoundsException Thrown when the index is not the range {@code 0 <= index <= size}. 3107 */ 3108 protected void validateIndex(final int index) { 3109 if (index < 0 || index >= size) { 3110 throw new StringIndexOutOfBoundsException(index); 3111 } 3112 } 3113 3114 /** 3115 * Validates parameters defining a range of the builder. 3116 * 3117 * @param startIndex the start index, inclusive, must be valid 3118 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 3119 * @return A valid end index. 3120 * @throws StringIndexOutOfBoundsException if the index is invalid 3121 */ 3122 protected int validateRange(final int startIndex, int endIndex) { 3123 if (startIndex < 0) { 3124 throw new StringIndexOutOfBoundsException(startIndex); 3125 } 3126 if (endIndex > size) { 3127 endIndex = size; 3128 } 3129 if (startIndex > endIndex) { 3130 throw new StringIndexOutOfBoundsException("end < start"); 3131 } 3132 return endIndex; 3133 } 3134 3135}