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