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