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