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