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