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