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.lang3.text; 018 019import java.util.regex.Matcher; 020import java.util.regex.Pattern; 021 022import org.apache.commons.lang3.ArrayUtils; 023import org.apache.commons.lang3.StringUtils; 024 025/** 026 * <p>Operations on Strings that contain words.</p> 027 * 028 * <p>This class tries to handle <code>null</code> input gracefully. 029 * An exception will not be thrown for a <code>null</code> input. 030 * Each method documents its behaviour in more detail.</p> 031 * 032 * @since 2.0 033 * @deprecated as of 3.6, use commons-text 034 * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/WordUtils.html"> 035 * WordUtils</a> instead 036 */ 037@Deprecated 038public class WordUtils { 039 040 /** 041 * <p><code>WordUtils</code> instances should NOT be constructed in 042 * standard programming. Instead, the class should be used as 043 * <code>WordUtils.wrap("foo bar", 20);</code>.</p> 044 * 045 * <p>This constructor is public to permit tools that require a JavaBean 046 * instance to operate.</p> 047 */ 048 public WordUtils() { 049 super(); 050 } 051 052 // Wrapping 053 //-------------------------------------------------------------------------- 054 /** 055 * <p>Wraps a single line of text, identifying words by <code>' '</code>.</p> 056 * 057 * <p>New lines will be separated by the system property line separator. 058 * Very long words, such as URLs will <i>not</i> be wrapped.</p> 059 * 060 * <p>Leading spaces on a new line are stripped. 061 * Trailing spaces are not stripped.</p> 062 * 063 * <table border="1" summary="Wrap Results"> 064 * <tr> 065 * <th>input</th> 066 * <th>wrapLength</th> 067 * <th>result</th> 068 * </tr> 069 * <tr> 070 * <td>null</td> 071 * <td>*</td> 072 * <td>null</td> 073 * </tr> 074 * <tr> 075 * <td>""</td> 076 * <td>*</td> 077 * <td>""</td> 078 * </tr> 079 * <tr> 080 * <td>"Here is one line of text that is going to be wrapped after 20 columns."</td> 081 * <td>20</td> 082 * <td>"Here is one line of\ntext that is going\nto be wrapped after\n20 columns."</td> 083 * </tr> 084 * <tr> 085 * <td>"Click here to jump to the commons website - http://commons.apache.org"</td> 086 * <td>20</td> 087 * <td>"Click here to jump\nto the commons\nwebsite -\nhttp://commons.apache.org"</td> 088 * </tr> 089 * <tr> 090 * <td>"Click here, http://commons.apache.org, to jump to the commons website"</td> 091 * <td>20</td> 092 * <td>"Click here,\nhttp://commons.apache.org,\nto jump to the\ncommons website"</td> 093 * </tr> 094 * </table> 095 * 096 * (assuming that '\n' is the systems line separator) 097 * 098 * @param str the String to be word wrapped, may be null 099 * @param wrapLength the column to wrap the words at, less than 1 is treated as 1 100 * @return a line with newlines inserted, <code>null</code> if null input 101 */ 102 public static String wrap(final String str, final int wrapLength) { 103 return wrap(str, wrapLength, null, false); 104 } 105 106 /** 107 * <p>Wraps a single line of text, identifying words by <code>' '</code>.</p> 108 * 109 * <p>Leading spaces on a new line are stripped. 110 * Trailing spaces are not stripped.</p> 111 * 112 * <table border="1" summary="Wrap Results"> 113 * <tr> 114 * <th>input</th> 115 * <th>wrapLength</th> 116 * <th>newLineString</th> 117 * <th>wrapLongWords</th> 118 * <th>result</th> 119 * </tr> 120 * <tr> 121 * <td>null</td> 122 * <td>*</td> 123 * <td>*</td> 124 * <td>true/false</td> 125 * <td>null</td> 126 * </tr> 127 * <tr> 128 * <td>""</td> 129 * <td>*</td> 130 * <td>*</td> 131 * <td>true/false</td> 132 * <td>""</td> 133 * </tr> 134 * <tr> 135 * <td>"Here is one line of text that is going to be wrapped after 20 columns."</td> 136 * <td>20</td> 137 * <td>"\n"</td> 138 * <td>true/false</td> 139 * <td>"Here is one line of\ntext that is going\nto be wrapped after\n20 columns."</td> 140 * </tr> 141 * <tr> 142 * <td>"Here is one line of text that is going to be wrapped after 20 columns."</td> 143 * <td>20</td> 144 * <td>"<br />"</td> 145 * <td>true/false</td> 146 * <td>"Here is one line of<br />text that is going<br />to be wrapped after<br />20 columns."</td> 147 * </tr> 148 * <tr> 149 * <td>"Here is one line of text that is going to be wrapped after 20 columns."</td> 150 * <td>20</td> 151 * <td>null</td> 152 * <td>true/false</td> 153 * <td>"Here is one line of" + systemNewLine + "text that is going" + systemNewLine + "to be wrapped after" + systemNewLine + "20 columns."</td> 154 * </tr> 155 * <tr> 156 * <td>"Click here to jump to the commons website - http://commons.apache.org"</td> 157 * <td>20</td> 158 * <td>"\n"</td> 159 * <td>false</td> 160 * <td>"Click here to jump\nto the commons\nwebsite -\nhttp://commons.apache.org"</td> 161 * </tr> 162 * <tr> 163 * <td>"Click here to jump to the commons website - http://commons.apache.org"</td> 164 * <td>20</td> 165 * <td>"\n"</td> 166 * <td>true</td> 167 * <td>"Click here to jump\nto the commons\nwebsite -\nhttp://commons.apach\ne.org"</td> 168 * </tr> 169 * </table> 170 * 171 * @param str the String to be word wrapped, may be null 172 * @param wrapLength the column to wrap the words at, less than 1 is treated as 1 173 * @param newLineStr the string to insert for a new line, 174 * <code>null</code> uses the system property line separator 175 * @param wrapLongWords true if long words (such as URLs) should be wrapped 176 * @return a line with newlines inserted, <code>null</code> if null input 177 */ 178 public static String wrap(final String str, final int wrapLength, final String newLineStr, final boolean wrapLongWords) { 179 return wrap(str, wrapLength, newLineStr, wrapLongWords, " "); 180 } 181 182 /** 183 * <p>Wraps a single line of text, identifying words by <code>wrapOn</code>.</p> 184 * 185 * <p>Leading spaces on a new line are stripped. 186 * Trailing spaces are not stripped.</p> 187 * 188 * <table border="1" summary="Wrap Results"> 189 * <tr> 190 * <th>input</th> 191 * <th>wrapLength</th> 192 * <th>newLineString</th> 193 * <th>wrapLongWords</th> 194 * <th>wrapOn</th> 195 * <th>result</th> 196 * </tr> 197 * <tr> 198 * <td>null</td> 199 * <td>*</td> 200 * <td>*</td> 201 * <td>true/false</td> 202 * <td>*</td> 203 * <td>null</td> 204 * </tr> 205 * <tr> 206 * <td>""</td> 207 * <td>*</td> 208 * <td>*</td> 209 * <td>true/false</td> 210 * <td>*</td> 211 * <td>""</td> 212 * </tr> 213 * <tr> 214 * <td>"Here is one line of text that is going to be wrapped after 20 columns."</td> 215 * <td>20</td> 216 * <td>"\n"</td> 217 * <td>true/false</td> 218 * <td>" "</td> 219 * <td>"Here is one line of\ntext that is going\nto be wrapped after\n20 columns."</td> 220 * </tr> 221 * <tr> 222 * <td>"Here is one line of text that is going to be wrapped after 20 columns."</td> 223 * <td>20</td> 224 * <td>"<br />"</td> 225 * <td>true/false</td> 226 * <td>" "</td> 227 * <td>"Here is one line of<br />text that is going<br />to be wrapped after<br />20 columns."</td> 228 * </tr> 229 * <tr> 230 * <td>"Here is one line of text that is going to be wrapped after 20 columns."</td> 231 * <td>20</td> 232 * <td>null</td> 233 * <td>true/false</td> 234 * <td>" "</td> 235 * <td>"Here is one line of" + systemNewLine + "text that is going" + systemNewLine + "to be wrapped after" + systemNewLine + "20 columns."</td> 236 * </tr> 237 * <tr> 238 * <td>"Click here to jump to the commons website - http://commons.apache.org"</td> 239 * <td>20</td> 240 * <td>"\n"</td> 241 * <td>false</td> 242 * <td>" "</td> 243 * <td>"Click here to jump\nto the commons\nwebsite -\nhttp://commons.apache.org"</td> 244 * </tr> 245 * <tr> 246 * <td>"Click here to jump to the commons website - http://commons.apache.org"</td> 247 * <td>20</td> 248 * <td>"\n"</td> 249 * <td>true</td> 250 * <td>" "</td> 251 * <td>"Click here to jump\nto the commons\nwebsite -\nhttp://commons.apach\ne.org"</td> 252 * </tr> 253 * <tr> 254 * <td>"flammable/inflammable"</td> 255 * <td>20</td> 256 * <td>"\n"</td> 257 * <td>true</td> 258 * <td>"/"</td> 259 * <td>"flammable\ninflammable"</td> 260 * </tr> 261 * </table> 262 * @param str the String to be word wrapped, may be null 263 * @param wrapLength the column to wrap the words at, less than 1 is treated as 1 264 * @param newLineStr the string to insert for a new line, 265 * <code>null</code> uses the system property line separator 266 * @param wrapLongWords true if long words (such as URLs) should be wrapped 267 * @param wrapOn regex expression to be used as a breakable characters, 268 * if blank string is provided a space character will be used 269 * @return a line with newlines inserted, <code>null</code> if null input 270 */ 271 public static String wrap(final String str, int wrapLength, String newLineStr, final boolean wrapLongWords, String wrapOn) { 272 if (str == null) { 273 return null; 274 } 275 if (newLineStr == null) { 276 newLineStr = System.lineSeparator(); 277 } 278 if (wrapLength < 1) { 279 wrapLength = 1; 280 } 281 if (StringUtils.isBlank(wrapOn)) { 282 wrapOn = " "; 283 } 284 final Pattern patternToWrapOn = Pattern.compile(wrapOn); 285 final int inputLineLength = str.length(); 286 int offset = 0; 287 final StringBuilder wrappedLine = new StringBuilder(inputLineLength + 32); 288 289 while (offset < inputLineLength) { 290 int spaceToWrapAt = -1; 291 Matcher matcher = patternToWrapOn.matcher(str.substring(offset, Math.min(offset + wrapLength + 1, inputLineLength))); 292 if (matcher.find()) { 293 if (matcher.start() == 0) { 294 offset += matcher.end(); 295 continue; 296 } 297 spaceToWrapAt = matcher.start() + offset; 298 } 299 300 // only last line without leading spaces is left 301 if(inputLineLength - offset <= wrapLength) { 302 break; 303 } 304 305 while(matcher.find()){ 306 spaceToWrapAt = matcher.start() + offset; 307 } 308 309 if (spaceToWrapAt >= offset) { 310 // normal case 311 wrappedLine.append(str.substring(offset, spaceToWrapAt)); 312 wrappedLine.append(newLineStr); 313 offset = spaceToWrapAt + 1; 314 315 } else { 316 // really long word or URL 317 if (wrapLongWords) { 318 // wrap really long word one line at a time 319 wrappedLine.append(str.substring(offset, wrapLength + offset)); 320 wrappedLine.append(newLineStr); 321 offset += wrapLength; 322 } else { 323 // do not wrap really long word, just extend beyond limit 324 matcher = patternToWrapOn.matcher(str.substring(offset + wrapLength)); 325 if (matcher.find()) { 326 spaceToWrapAt = matcher.start() + offset + wrapLength; 327 } 328 329 if (spaceToWrapAt >= 0) { 330 wrappedLine.append(str.substring(offset, spaceToWrapAt)); 331 wrappedLine.append(newLineStr); 332 offset = spaceToWrapAt + 1; 333 } else { 334 wrappedLine.append(str.substring(offset)); 335 offset = inputLineLength; 336 } 337 } 338 } 339 } 340 341 // Whatever is left in line is short enough to just pass through 342 wrappedLine.append(str.substring(offset)); 343 344 return wrappedLine.toString(); 345 } 346 347 // Capitalizing 348 //----------------------------------------------------------------------- 349 /** 350 * <p>Capitalizes all the whitespace separated words in a String. 351 * Only the first character of each word is changed. To convert the 352 * rest of each word to lowercase at the same time, 353 * use {@link #capitalizeFully(String)}.</p> 354 * 355 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}. 356 * A <code>null</code> input String returns <code>null</code>. 357 * Capitalization uses the Unicode title case, normally equivalent to 358 * upper case.</p> 359 * 360 * <pre> 361 * WordUtils.capitalize(null) = null 362 * WordUtils.capitalize("") = "" 363 * WordUtils.capitalize("i am FINE") = "I Am FINE" 364 * </pre> 365 * 366 * @param str the String to capitalize, may be null 367 * @return capitalized String, <code>null</code> if null String input 368 * @see #uncapitalize(String) 369 * @see #capitalizeFully(String) 370 */ 371 public static String capitalize(final String str) { 372 return capitalize(str, null); 373 } 374 375 /** 376 * <p>Capitalizes all the delimiter separated words in a String. 377 * Only the first character of each word is changed. To convert the 378 * rest of each word to lowercase at the same time, 379 * use {@link #capitalizeFully(String, char[])}.</p> 380 * 381 * <p>The delimiters represent a set of characters understood to separate words. 382 * The first string character and the first non-delimiter character after a 383 * delimiter will be capitalized. </p> 384 * 385 * <p>A <code>null</code> input String returns <code>null</code>. 386 * Capitalization uses the Unicode title case, normally equivalent to 387 * upper case.</p> 388 * 389 * <pre> 390 * WordUtils.capitalize(null, *) = null 391 * WordUtils.capitalize("", *) = "" 392 * WordUtils.capitalize(*, new char[0]) = * 393 * WordUtils.capitalize("i am fine", null) = "I Am Fine" 394 * WordUtils.capitalize("i aM.fine", {'.'}) = "I aM.Fine" 395 * </pre> 396 * 397 * @param str the String to capitalize, may be null 398 * @param delimiters set of characters to determine capitalization, null means whitespace 399 * @return capitalized String, <code>null</code> if null String input 400 * @see #uncapitalize(String) 401 * @see #capitalizeFully(String) 402 * @since 2.1 403 */ 404 public static String capitalize(final String str, final char... delimiters) { 405 final int delimLen = delimiters == null ? -1 : delimiters.length; 406 if (StringUtils.isEmpty(str) || delimLen == 0) { 407 return str; 408 } 409 final char[] buffer = str.toCharArray(); 410 boolean capitalizeNext = true; 411 for (int i = 0; i < buffer.length; i++) { 412 final char ch = buffer[i]; 413 if (isDelimiter(ch, delimiters)) { 414 capitalizeNext = true; 415 } else if (capitalizeNext) { 416 buffer[i] = Character.toTitleCase(ch); 417 capitalizeNext = false; 418 } 419 } 420 return new String(buffer); 421 } 422 423 //----------------------------------------------------------------------- 424 /** 425 * <p>Converts all the whitespace separated words in a String into capitalized words, 426 * that is each word is made up of a titlecase character and then a series of 427 * lowercase characters. </p> 428 * 429 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}. 430 * A <code>null</code> input String returns <code>null</code>. 431 * Capitalization uses the Unicode title case, normally equivalent to 432 * upper case.</p> 433 * 434 * <pre> 435 * WordUtils.capitalizeFully(null) = null 436 * WordUtils.capitalizeFully("") = "" 437 * WordUtils.capitalizeFully("i am FINE") = "I Am Fine" 438 * </pre> 439 * 440 * @param str the String to capitalize, may be null 441 * @return capitalized String, <code>null</code> if null String input 442 */ 443 public static String capitalizeFully(final String str) { 444 return capitalizeFully(str, null); 445 } 446 447 /** 448 * <p>Converts all the delimiter separated words in a String into capitalized words, 449 * that is each word is made up of a titlecase character and then a series of 450 * lowercase characters. </p> 451 * 452 * <p>The delimiters represent a set of characters understood to separate words. 453 * The first string character and the first non-delimiter character after a 454 * delimiter will be capitalized. </p> 455 * 456 * <p>A <code>null</code> input String returns <code>null</code>. 457 * Capitalization uses the Unicode title case, normally equivalent to 458 * upper case.</p> 459 * 460 * <pre> 461 * WordUtils.capitalizeFully(null, *) = null 462 * WordUtils.capitalizeFully("", *) = "" 463 * WordUtils.capitalizeFully(*, null) = * 464 * WordUtils.capitalizeFully(*, new char[0]) = * 465 * WordUtils.capitalizeFully("i aM.fine", {'.'}) = "I am.Fine" 466 * </pre> 467 * 468 * @param str the String to capitalize, may be null 469 * @param delimiters set of characters to determine capitalization, null means whitespace 470 * @return capitalized String, <code>null</code> if null String input 471 * @since 2.1 472 */ 473 public static String capitalizeFully(String str, final char... delimiters) { 474 final int delimLen = delimiters == null ? -1 : delimiters.length; 475 if (StringUtils.isEmpty(str) || delimLen == 0) { 476 return str; 477 } 478 str = str.toLowerCase(); 479 return capitalize(str, delimiters); 480 } 481 482 //----------------------------------------------------------------------- 483 /** 484 * <p>Uncapitalizes all the whitespace separated words in a String. 485 * Only the first character of each word is changed.</p> 486 * 487 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}. 488 * A <code>null</code> input String returns <code>null</code>.</p> 489 * 490 * <pre> 491 * WordUtils.uncapitalize(null) = null 492 * WordUtils.uncapitalize("") = "" 493 * WordUtils.uncapitalize("I Am FINE") = "i am fINE" 494 * </pre> 495 * 496 * @param str the String to uncapitalize, may be null 497 * @return uncapitalized String, <code>null</code> if null String input 498 * @see #capitalize(String) 499 */ 500 public static String uncapitalize(final String str) { 501 return uncapitalize(str, null); 502 } 503 504 /** 505 * <p>Uncapitalizes all the whitespace separated words in a String. 506 * Only the first character of each word is changed.</p> 507 * 508 * <p>The delimiters represent a set of characters understood to separate words. 509 * The first string character and the first non-delimiter character after a 510 * delimiter will be uncapitalized. </p> 511 * 512 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}. 513 * A <code>null</code> input String returns <code>null</code>.</p> 514 * 515 * <pre> 516 * WordUtils.uncapitalize(null, *) = null 517 * WordUtils.uncapitalize("", *) = "" 518 * WordUtils.uncapitalize(*, null) = * 519 * WordUtils.uncapitalize(*, new char[0]) = * 520 * WordUtils.uncapitalize("I AM.FINE", {'.'}) = "i AM.fINE" 521 * </pre> 522 * 523 * @param str the String to uncapitalize, may be null 524 * @param delimiters set of characters to determine uncapitalization, null means whitespace 525 * @return uncapitalized String, <code>null</code> if null String input 526 * @see #capitalize(String) 527 * @since 2.1 528 */ 529 public static String uncapitalize(final String str, final char... delimiters) { 530 final int delimLen = delimiters == null ? -1 : delimiters.length; 531 if (StringUtils.isEmpty(str) || delimLen == 0) { 532 return str; 533 } 534 final char[] buffer = str.toCharArray(); 535 boolean uncapitalizeNext = true; 536 for (int i = 0; i < buffer.length; i++) { 537 final char ch = buffer[i]; 538 if (isDelimiter(ch, delimiters)) { 539 uncapitalizeNext = true; 540 } else if (uncapitalizeNext) { 541 buffer[i] = Character.toLowerCase(ch); 542 uncapitalizeNext = false; 543 } 544 } 545 return new String(buffer); 546 } 547 548 //----------------------------------------------------------------------- 549 /** 550 * <p>Swaps the case of a String using a word based algorithm.</p> 551 * 552 * <ul> 553 * <li>Upper case character converts to Lower case</li> 554 * <li>Title case character converts to Lower case</li> 555 * <li>Lower case character after Whitespace or at start converts to Title case</li> 556 * <li>Other Lower case character converts to Upper case</li> 557 * </ul> 558 * 559 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}. 560 * A <code>null</code> input String returns <code>null</code>.</p> 561 * 562 * <pre> 563 * StringUtils.swapCase(null) = null 564 * StringUtils.swapCase("") = "" 565 * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone" 566 * </pre> 567 * 568 * @param str the String to swap case, may be null 569 * @return the changed String, <code>null</code> if null String input 570 */ 571 public static String swapCase(final String str) { 572 if (StringUtils.isEmpty(str)) { 573 return str; 574 } 575 final char[] buffer = str.toCharArray(); 576 577 boolean whitespace = true; 578 579 for (int i = 0; i < buffer.length; i++) { 580 final char ch = buffer[i]; 581 if (Character.isUpperCase(ch)) { 582 buffer[i] = Character.toLowerCase(ch); 583 whitespace = false; 584 } else if (Character.isTitleCase(ch)) { 585 buffer[i] = Character.toLowerCase(ch); 586 whitespace = false; 587 } else if (Character.isLowerCase(ch)) { 588 if (whitespace) { 589 buffer[i] = Character.toTitleCase(ch); 590 whitespace = false; 591 } else { 592 buffer[i] = Character.toUpperCase(ch); 593 } 594 } else { 595 whitespace = Character.isWhitespace(ch); 596 } 597 } 598 return new String(buffer); 599 } 600 601 //----------------------------------------------------------------------- 602 /** 603 * <p>Extracts the initial characters from each word in the String.</p> 604 * 605 * <p>All first characters after whitespace are returned as a new string. 606 * Their case is not changed.</p> 607 * 608 * <p>Whitespace is defined by {@link Character#isWhitespace(char)}. 609 * A <code>null</code> input String returns <code>null</code>.</p> 610 * 611 * <pre> 612 * WordUtils.initials(null) = null 613 * WordUtils.initials("") = "" 614 * WordUtils.initials("Ben John Lee") = "BJL" 615 * WordUtils.initials("Ben J.Lee") = "BJ" 616 * </pre> 617 * 618 * @param str the String to get initials from, may be null 619 * @return String of initial letters, <code>null</code> if null String input 620 * @see #initials(String,char[]) 621 * @since 2.2 622 */ 623 public static String initials(final String str) { 624 return initials(str, null); 625 } 626 627 /** 628 * <p>Extracts the initial characters from each word in the String.</p> 629 * 630 * <p>All first characters after the defined delimiters are returned as a new string. 631 * Their case is not changed.</p> 632 * 633 * <p>If the delimiters array is null, then Whitespace is used. 634 * Whitespace is defined by {@link Character#isWhitespace(char)}. 635 * A <code>null</code> input String returns <code>null</code>. 636 * An empty delimiter array returns an empty String.</p> 637 * 638 * <pre> 639 * WordUtils.initials(null, *) = null 640 * WordUtils.initials("", *) = "" 641 * WordUtils.initials("Ben John Lee", null) = "BJL" 642 * WordUtils.initials("Ben J.Lee", null) = "BJ" 643 * WordUtils.initials("Ben J.Lee", [' ','.']) = "BJL" 644 * WordUtils.initials(*, new char[0]) = "" 645 * </pre> 646 * 647 * @param str the String to get initials from, may be null 648 * @param delimiters set of characters to determine words, null means whitespace 649 * @return String of initial characters, <code>null</code> if null String input 650 * @see #initials(String) 651 * @since 2.2 652 */ 653 public static String initials(final String str, final char... delimiters) { 654 if (StringUtils.isEmpty(str)) { 655 return str; 656 } 657 if (delimiters != null && delimiters.length == 0) { 658 return StringUtils.EMPTY; 659 } 660 final int strLen = str.length(); 661 final char[] buf = new char[strLen / 2 + 1]; 662 int count = 0; 663 boolean lastWasGap = true; 664 for (int i = 0; i < strLen; i++) { 665 final char ch = str.charAt(i); 666 667 if (isDelimiter(ch, delimiters)) { 668 lastWasGap = true; 669 } else if (lastWasGap) { 670 buf[count++] = ch; 671 lastWasGap = false; 672 } else { 673 continue; // ignore ch 674 } 675 } 676 return new String(buf, 0, count); 677 } 678 679 //----------------------------------------------------------------------- 680 /** 681 * <p>Checks if the String contains all words in the given array.</p> 682 * 683 * <p> 684 * A {@code null} String will return {@code false}. A {@code null}, zero 685 * length search array or if one element of array is null will return {@code false}. 686 * </p> 687 * 688 * <pre> 689 * WordUtils.containsAllWords(null, *) = false 690 * WordUtils.containsAllWords("", *) = false 691 * WordUtils.containsAllWords(*, null) = false 692 * WordUtils.containsAllWords(*, []) = false 693 * WordUtils.containsAllWords("abcd", "ab", "cd") = false 694 * WordUtils.containsAllWords("abc def", "def", "abc") = true 695 * </pre> 696 * 697 * 698 * @param word The CharSequence to check, may be null 699 * @param words The array of String words to search for, may be null 700 * @return {@code true} if all search words are found, {@code false} otherwise 701 * @since 3.5 702 */ 703 public static boolean containsAllWords(final CharSequence word, final CharSequence... words) { 704 if (StringUtils.isEmpty(word) || ArrayUtils.isEmpty(words)) { 705 return false; 706 } 707 for (final CharSequence w : words) { 708 if (StringUtils.isBlank(w)) { 709 return false; 710 } 711 final Pattern p = Pattern.compile(".*\\b" + w + "\\b.*"); 712 if (!p.matcher(word).matches()) { 713 return false; 714 } 715 } 716 return true; 717 } 718 719 //----------------------------------------------------------------------- 720 /** 721 * Is the character a delimiter. 722 * 723 * @param ch the character to check 724 * @param delimiters the delimiters 725 * @return true if it is a delimiter 726 */ 727 private static boolean isDelimiter(final char ch, final char[] delimiters) { 728 if (delimiters == null) { 729 return Character.isWhitespace(ch); 730 } 731 for (final char delimiter : delimiters) { 732 if (ch == delimiter) { 733 return true; 734 } 735 } 736 return false; 737 } 738 739}