StringUtils.java 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. /**
  2. * Copyright (c) 2011-2014, hubin (jobob@qq.com).
  3. * <p>
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. * <p>
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. * <p>
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.baomidou.mybatisplus.toolkit;
  17. import java.util.ArrayList;
  18. import java.util.Collection;
  19. import java.util.Collections;
  20. import java.util.Iterator;
  21. import java.util.List;
  22. import java.util.regex.Matcher;
  23. import java.util.regex.Pattern;
  24. /**
  25. * <p>
  26. * String 工具类
  27. * </p>
  28. *
  29. * @author D.Yang
  30. * @Date 2016-08-18
  31. */
  32. public class StringUtils {
  33. /**
  34. * 空字符
  35. */
  36. public static final String EMPTY = "";
  37. /**
  38. * 字符串 is
  39. */
  40. public static final String IS = "is";
  41. /**
  42. * 下划线字符
  43. */
  44. public static final char UNDERLINE = '_';
  45. /**
  46. * 占位符
  47. */
  48. public static final String PLACE_HOLDER = "{%s}";
  49. private static boolean separatorBeforeDigit = false;
  50. private static boolean separatorAfterDigit = true;
  51. private StringUtils() {
  52. }
  53. /**
  54. * <p>
  55. * 判断字符串是否为空
  56. * </p>
  57. *
  58. * @param cs 需要判断字符串
  59. * @return 判断结果
  60. */
  61. public static boolean isEmpty(final CharSequence cs) {
  62. int strLen;
  63. if (cs == null || (strLen = cs.length()) == 0) {
  64. return true;
  65. }
  66. for (int i = 0; i < strLen; i++) {
  67. if (!Character.isWhitespace(cs.charAt(i))) {
  68. return false;
  69. }
  70. }
  71. return true;
  72. }
  73. /**
  74. * <p>
  75. * 判断字符串是否不为空
  76. * </p>
  77. *
  78. * @param cs 需要判断字符串
  79. * @return 判断结果
  80. */
  81. public static boolean isNotEmpty(final CharSequence cs) {
  82. return !isEmpty(cs);
  83. }
  84. /**
  85. * <p>
  86. * 字符串驼峰转下划线格式
  87. * </p>
  88. *
  89. * @param param 需要转换的字符串
  90. * @return 转换好的字符串
  91. */
  92. public static String camelToUnderline(String param) {
  93. if (isEmpty(param)) {
  94. return EMPTY;
  95. }
  96. int len = param.length();
  97. StringBuilder sb = new StringBuilder(len);
  98. for (int i = 0; i < len; i++) {
  99. char c = param.charAt(i);
  100. if (Character.isUpperCase(c) && i > 0) {
  101. sb.append(UNDERLINE);
  102. }
  103. sb.append(Character.toLowerCase(c));
  104. }
  105. return sb.toString();
  106. }
  107. /**
  108. * <p>
  109. * 字符串下划线转驼峰格式
  110. * </p>
  111. *
  112. * @param param 需要转换的字符串
  113. * @return 转换好的字符串
  114. */
  115. public static String underlineToCamel(String param) {
  116. if (isEmpty(param)) {
  117. return EMPTY;
  118. }
  119. String temp = param.toLowerCase();
  120. int len = temp.length();
  121. StringBuilder sb = new StringBuilder(len);
  122. for (int i = 0; i < len; i++) {
  123. char c = temp.charAt(i);
  124. if (c == UNDERLINE) {
  125. if (++i < len) {
  126. sb.append(Character.toUpperCase(temp.charAt(i)));
  127. }
  128. } else {
  129. sb.append(c);
  130. }
  131. }
  132. return sb.toString();
  133. }
  134. /**
  135. * <p>
  136. * 首字母转换小写
  137. * </p>
  138. *
  139. * @param param 需要转换的字符串
  140. * @return 转换好的字符串
  141. */
  142. public static String firstToLowerCase(String param) {
  143. if (isEmpty(param)) {
  144. return EMPTY;
  145. }
  146. StringBuilder sb = new StringBuilder(param.length());
  147. sb.append(param.substring(0, 1).toLowerCase());
  148. sb.append(param.substring(1));
  149. return sb.toString();
  150. }
  151. /**
  152. * <p>
  153. * 判断字符串是否为纯大写字母
  154. * </p>
  155. *
  156. * @param str 要匹配的字符串
  157. * @return
  158. */
  159. public static boolean isUpperCase(String str) {
  160. return match("^[A-Z]+$", str);
  161. }
  162. /**
  163. * <p>
  164. * 正则表达式匹配
  165. * </p>
  166. *
  167. * @param regex 正则表达式字符串
  168. * @param str 要匹配的字符串
  169. * @return 如果str 符合 regex的正则表达式格式,返回true, 否则返回 false;
  170. */
  171. public static boolean match(String regex, String str) {
  172. Pattern pattern = Pattern.compile(regex);
  173. Matcher matcher = pattern.matcher(str);
  174. return matcher.matches();
  175. }
  176. /**
  177. * <p>
  178. * SQL 参数填充
  179. * </p>
  180. *
  181. * @param content 填充内容
  182. * @param args 填充参数
  183. * @return
  184. */
  185. public static String sqlArgsFill(String content, Object... args) {
  186. if (StringUtils.isEmpty(content)) {
  187. return null;
  188. }
  189. if (args != null) {
  190. int length = args.length;
  191. if (length >= 1) {
  192. for (int i = 0; i < length; i++) {
  193. content = content.replace(String.format(PLACE_HOLDER, i), sqlParam(args[i]));
  194. }
  195. }
  196. }
  197. return content;
  198. }
  199. /**
  200. * <p>
  201. * 获取SQL PARAMS字符串
  202. * </p>
  203. *
  204. * @param obj
  205. * @return
  206. */
  207. public static String sqlParam(Object obj) {
  208. String repStr;
  209. if (obj instanceof Collection) {
  210. repStr = StringUtils.quotaMarkList((Collection<?>) obj);
  211. } else {
  212. repStr = StringUtils.quotaMark(obj);
  213. }
  214. return repStr;
  215. }
  216. /**
  217. * <p>
  218. * 使用单引号包含字符串
  219. * </p>
  220. *
  221. * @param obj 原字符串
  222. * @return 单引号包含的原字符串
  223. */
  224. public static String quotaMark(Object obj) {
  225. String srcStr = String.valueOf(obj);
  226. if (obj instanceof CharSequence) {
  227. // fix #79
  228. return StringEscape.escapeString(srcStr);
  229. }
  230. return srcStr;
  231. }
  232. /**
  233. * <p>
  234. * 使用单引号包含字符串
  235. * </p>
  236. *
  237. * @param coll 集合
  238. * @return 单引号包含的原字符串的集合形式
  239. */
  240. public static String quotaMarkList(Collection<?> coll) {
  241. StringBuilder sqlBuild = new StringBuilder();
  242. sqlBuild.append("(");
  243. int size = coll.size();
  244. int i = 0;
  245. Iterator<?> iterator = coll.iterator();
  246. while (iterator.hasNext()) {
  247. String tempVal = StringUtils.quotaMark(iterator.next());
  248. sqlBuild.append(tempVal);
  249. if (i + 1 < size) {
  250. sqlBuild.append(",");
  251. }
  252. i++;
  253. }
  254. sqlBuild.append(")");
  255. return sqlBuild.toString();
  256. }
  257. /**
  258. * <p>
  259. * 拼接字符串第二个字符串第一个字母大写
  260. * </p>
  261. *
  262. * @param concatStr
  263. * @param str
  264. * @return
  265. */
  266. public static String concatCapitalize(String concatStr, final String str) {
  267. if (isEmpty(concatStr)) {
  268. concatStr = EMPTY;
  269. }
  270. int strLen;
  271. if (str == null || (strLen = str.length()) == 0) {
  272. return str;
  273. }
  274. final char firstChar = str.charAt(0);
  275. if (Character.isTitleCase(firstChar)) {
  276. // already capitalized
  277. return str;
  278. }
  279. StringBuilder sb = new StringBuilder(strLen);
  280. sb.append(concatStr);
  281. sb.append(Character.toTitleCase(firstChar));
  282. sb.append(str.substring(1));
  283. return sb.toString();
  284. }
  285. /**
  286. * <p>
  287. * 字符串第一个字母大写
  288. * </p>
  289. *
  290. * @param str
  291. * @return
  292. */
  293. public static String capitalize(final String str) {
  294. return concatCapitalize(null, str);
  295. }
  296. /**
  297. * <p>
  298. * 判断对象是否为空
  299. * </p>
  300. *
  301. * @param object
  302. * @return
  303. */
  304. public static boolean checkValNotNull(Object object) {
  305. if (object instanceof CharSequence) {
  306. return isNotEmpty((CharSequence) object);
  307. }
  308. return object != null;
  309. }
  310. /**
  311. * <p>
  312. * 判断对象是否为空
  313. * </p>
  314. *
  315. * @param object
  316. * @return
  317. */
  318. public static boolean checkValNull(Object object) {
  319. return !checkValNotNull(object);
  320. }
  321. /**
  322. * <p>
  323. * 包含大写字母
  324. * </p>
  325. *
  326. * @param word 待判断字符串
  327. * @return
  328. */
  329. public static boolean containsUpperCase(String word) {
  330. for (int i = 0; i < word.length(); i++) {
  331. char c = word.charAt(i);
  332. if (Character.isUpperCase(c)) {
  333. return true;
  334. }
  335. }
  336. return false;
  337. }
  338. /**
  339. * <p>
  340. * 是否为大写命名
  341. * </p>
  342. *
  343. * @param word 待判断字符串
  344. * @return
  345. */
  346. public static boolean isCapitalMode(String word) {
  347. return null != word && word.matches("^[0-9A-Z/_]+$");
  348. }
  349. /**
  350. * <p>
  351. * 是否为驼峰下划线混合命名
  352. * </p>
  353. *
  354. * @param word 待判断字符串
  355. * @return
  356. */
  357. public static boolean isMixedMode(String word) {
  358. return Pattern.compile(".*[A-Z]+.*").matcher(word).matches() && Pattern.compile(".*[/_]+.*").matcher(word).matches();
  359. }
  360. /**
  361. * <p>
  362. * Check if a String ends with a specified suffix.
  363. * </p>
  364. * <p>
  365. * <p>
  366. * <code>null</code>s are handled without exceptions. Two <code>null</code>
  367. * references are considered to be equal. The comparison is case sensitive.
  368. * </p>
  369. * <p>
  370. * <pre>
  371. * StringUtils.endsWith(null, null) = true
  372. * StringUtils.endsWith(null, "abcdef") = false
  373. * StringUtils.endsWith("def", null) = false
  374. * StringUtils.endsWith("def", "abcdef") = true
  375. * StringUtils.endsWith("def", "ABCDEF") = false
  376. * </pre>
  377. *
  378. * @param str the String to check, may be null
  379. * @param suffix the suffix to find, may be null
  380. * @return <code>true</code> if the String ends with the suffix, case
  381. * sensitive, or both <code>null</code>
  382. * @see java.lang.String#endsWith(String)
  383. * @since 2.4
  384. */
  385. public static boolean endsWith(String str, String suffix) {
  386. return endsWith(str, suffix, false);
  387. }
  388. /**
  389. * <p>
  390. * Case insensitive check if a String ends with a specified suffix.
  391. * </p>
  392. * <p>
  393. * <p>
  394. * <code>null</code>s are handled without exceptions. Two <code>null</code>
  395. * references are considered to be equal. The comparison is case
  396. * insensitive.
  397. * </p>
  398. * <p>
  399. * <pre>
  400. * StringUtils.endsWithIgnoreCase(null, null) = true
  401. * StringUtils.endsWithIgnoreCase(null, "abcdef") = false
  402. * StringUtils.endsWithIgnoreCase("def", null) = false
  403. * StringUtils.endsWithIgnoreCase("def", "abcdef") = true
  404. * StringUtils.endsWithIgnoreCase("def", "ABCDEF") = false
  405. * </pre>
  406. *
  407. * @param str the String to check, may be null
  408. * @param suffix the suffix to find, may be null
  409. * @return <code>true</code> if the String ends with the suffix, case
  410. * insensitive, or both <code>null</code>
  411. * @see java.lang.String#endsWith(String)
  412. * @since 2.4
  413. */
  414. public static boolean endsWithIgnoreCase(String str, String suffix) {
  415. return endsWith(str, suffix, true);
  416. }
  417. /**
  418. * <p>
  419. * Check if a String ends with a specified suffix (optionally case
  420. * insensitive).
  421. * </p>
  422. *
  423. * @param str the String to check, may be null
  424. * @param suffix the suffix to find, may be null
  425. * @param ignoreCase inidicates whether the compare should ignore case (case
  426. * insensitive) or not.
  427. * @return <code>true</code> if the String starts with the prefix or both
  428. * <code>null</code>
  429. * @see java.lang.String#endsWith(String)
  430. */
  431. private static boolean endsWith(String str, String suffix, boolean ignoreCase) {
  432. if (str == null || suffix == null) {
  433. return (str == null && suffix == null);
  434. }
  435. if (suffix.length() > str.length()) {
  436. return false;
  437. }
  438. int strOffset = str.length() - suffix.length();
  439. return str.regionMatches(ignoreCase, strOffset, suffix, 0, suffix.length());
  440. }
  441. /**
  442. * <p>
  443. * Splits the provided text into an array, separators specified. This is an
  444. * alternative to using StringTokenizer.
  445. * </p>
  446. * <p>
  447. * <p>
  448. * The separator is not included in the returned String array. Adjacent
  449. * separators are treated as one separator. For more control over the split
  450. * use the StrTokenizer class.
  451. * </p>
  452. * <p>
  453. * <p>
  454. * A {@code null} input String returns {@code null}. A {@code null}
  455. * separatorChars splits on whitespace.
  456. * </p>
  457. * <p>
  458. * <pre>
  459. * StringUtils.split(null, *) = null
  460. * StringUtils.split("", *) = []
  461. * StringUtils.split("abc def", null) = ["abc", "def"]
  462. * StringUtils.split("abc def", " ") = ["abc", "def"]
  463. * StringUtils.split("abc def", " ") = ["abc", "def"]
  464. * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
  465. * </pre>
  466. *
  467. * @param str the String to parse, may be null
  468. * @param separatorChars the characters used as the delimiters, {@code null} splits on
  469. * whitespace
  470. * @return an array of parsed Strings, {@code null} if null String input
  471. */
  472. public static String[] split(final String str, final String separatorChars) {
  473. List<String> strings = splitWorker(str, separatorChars, -1, false);
  474. return strings.toArray(new String[strings.size()]);
  475. }
  476. /**
  477. * Performs the logic for the {@code split} and
  478. * {@code splitPreserveAllTokens} methods that return a maximum array
  479. * length.
  480. *
  481. * @param str the String to parse, may be {@code null}
  482. * @param separatorChars the separate character
  483. * @param max the maximum number of elements to include in the array. A zero
  484. * or negative value implies no limit.
  485. * @param preserveAllTokens if {@code true}, adjacent separators are treated as empty
  486. * token separators; if {@code false}, adjacent separators are
  487. * treated as one separator.
  488. * @return an array of parsed Strings, {@code null} if null String input
  489. */
  490. public static List<String> splitWorker(final String str, final String separatorChars, final int max,
  491. final boolean preserveAllTokens) {
  492. // Performance tuned for 2.0 (JDK1.4)
  493. // Direct code is quicker than StringTokenizer.
  494. // Also, StringTokenizer uses isSpace() not isWhitespace()
  495. if (str == null) {
  496. return null;
  497. }
  498. final int len = str.length();
  499. if (len == 0) {
  500. return Collections.emptyList();
  501. }
  502. final List<String> list = new ArrayList<>();
  503. int sizePlus1 = 1;
  504. int i = 0, start = 0;
  505. boolean match = false;
  506. boolean lastMatch = false;
  507. if (separatorChars == null) {
  508. // Null separator means use whitespace
  509. while (i < len) {
  510. if (Character.isWhitespace(str.charAt(i))) {
  511. if (match || preserveAllTokens) {
  512. lastMatch = true;
  513. if (sizePlus1++ == max) {
  514. i = len;
  515. lastMatch = false;
  516. }
  517. list.add(str.substring(start, i));
  518. match = false;
  519. }
  520. start = ++i;
  521. continue;
  522. }
  523. lastMatch = false;
  524. match = true;
  525. i++;
  526. }
  527. } else if (separatorChars.length() == 1) {
  528. // Optimise 1 character case
  529. final char sep = separatorChars.charAt(0);
  530. while (i < len) {
  531. if (str.charAt(i) == sep) {
  532. if (match || preserveAllTokens) {
  533. lastMatch = true;
  534. if (sizePlus1++ == max) {
  535. i = len;
  536. lastMatch = false;
  537. }
  538. list.add(str.substring(start, i));
  539. match = false;
  540. }
  541. start = ++i;
  542. continue;
  543. }
  544. lastMatch = false;
  545. match = true;
  546. i++;
  547. }
  548. } else {
  549. // standard case
  550. while (i < len) {
  551. if (separatorChars.indexOf(str.charAt(i)) >= 0) {
  552. if (match || preserveAllTokens) {
  553. lastMatch = true;
  554. if (sizePlus1++ == max) {
  555. i = len;
  556. lastMatch = false;
  557. }
  558. list.add(str.substring(start, i));
  559. match = false;
  560. }
  561. start = ++i;
  562. continue;
  563. }
  564. lastMatch = false;
  565. match = true;
  566. i++;
  567. }
  568. }
  569. if (match || preserveAllTokens && lastMatch) {
  570. list.add(str.substring(start, i));
  571. }
  572. return list;
  573. }
  574. /**
  575. * <p>
  576. * 是否为CharSequence类型
  577. * </p>
  578. *
  579. * @param cls
  580. * @return
  581. */
  582. public static Boolean isCharSequence(Class<?> cls) {
  583. return cls != null && CharSequence.class.isAssignableFrom(cls);
  584. }
  585. /**
  586. * <p>
  587. * 去除boolean类型is开头的字符串
  588. * </p>
  589. *
  590. * @param propertyName 字段名
  591. * @param propertyType 字段类型
  592. * @return
  593. */
  594. public static String removeIsPrefixIfBoolean(String propertyName, Class<?> propertyType) {
  595. if (isBoolean(propertyType) && propertyName.startsWith(IS)) {
  596. String property = propertyName.replaceFirst(IS, EMPTY);
  597. if (isEmpty(property)) {
  598. return propertyName;
  599. } else {
  600. String firstCharToLowerStr = firstCharToLower(property);
  601. return property.equals(firstCharToLowerStr) ? propertyName : firstCharToLowerStr;
  602. }
  603. }
  604. return propertyName;
  605. }
  606. /**
  607. * <p>
  608. * 是否为CharSequence类型
  609. * </p>
  610. *
  611. * @param propertyType
  612. * @return
  613. */
  614. public static Boolean isCharSequence(String propertyType) {
  615. try {
  616. return isCharSequence(Class.forName(propertyType));
  617. } catch (ClassNotFoundException e) {
  618. return false;
  619. }
  620. }
  621. /**
  622. * <p>
  623. * 是否为Boolean类型(包含普通类型)
  624. * </p>
  625. *
  626. * @param propertyCls
  627. * @return
  628. */
  629. public static Boolean isBoolean(Class<?> propertyCls) {
  630. return propertyCls != null && (boolean.class.isAssignableFrom(propertyCls) || Boolean.class.isAssignableFrom(propertyCls));
  631. }
  632. /**
  633. * <p>
  634. * 第一个首字母小写,之后字符大小写的不变<br>
  635. * StringUtils.firstCharToLower( "UserService" ) = userService
  636. * StringUtils.firstCharToLower( "UserServiceImpl" ) = userServiceImpl
  637. * </p>
  638. *
  639. * @param rawString 需要处理的字符串
  640. * @return
  641. */
  642. public static String firstCharToLower(String rawString) {
  643. return prefixToLower(rawString, 1);
  644. }
  645. /**
  646. * <p>
  647. * 前n个首字母小写,之后字符大小写的不变
  648. * </p>
  649. *
  650. * @param rawString 需要处理的字符串
  651. * @param index 多少个字符(从左至右)
  652. * @return
  653. */
  654. public static String prefixToLower(String rawString, int index) {
  655. String beforeChar = rawString.substring(0, index).toLowerCase();
  656. String afterChar = rawString.substring(index, rawString.length());
  657. return beforeChar + afterChar;
  658. }
  659. /**
  660. * <p>
  661. * 删除字符前缀之后,首字母小写,之后字符大小写的不变<br>
  662. * StringUtils.removePrefixAfterPrefixToLower( "isUser", 2 ) = user
  663. * StringUtils.removePrefixAfterPrefixToLower( "isUserInfo", 2 ) = userInfo
  664. * </p>
  665. *
  666. * @param rawString 需要处理的字符串
  667. * @param index 删除多少个字符(从左至右)
  668. * @return
  669. */
  670. public static String removePrefixAfterPrefixToLower(String rawString, int index) {
  671. return prefixToLower(rawString.substring(index, rawString.length()), 1);
  672. }
  673. /**
  674. * <p>
  675. * 驼峰转连字符<br>
  676. * StringUtils.camelToHyphen( "managerAdminUserService" ) = manager-admin-user-service
  677. * </p>
  678. *
  679. * @param input
  680. * @return 以'-'分隔
  681. * @see <a href="https://github.com/krasa/StringManipulation">document</a>
  682. */
  683. public static String camelToHyphen(String input) {
  684. return wordsToHyphenCase(wordsAndHyphenAndCamelToConstantCase(input));
  685. }
  686. private static String wordsAndHyphenAndCamelToConstantCase(String input) {
  687. boolean betweenUpperCases = false;
  688. boolean containsLowerCase = containsLowerCase(input);
  689. StringBuilder buf = new StringBuilder();
  690. char previousChar = ' ';
  691. char[] chars = input.toCharArray();
  692. for (int i = 0; i < chars.length; i++) {
  693. char c = chars[i];
  694. boolean isUpperCaseAndPreviousIsUpperCase = (Character.isUpperCase(previousChar)) && (Character.isUpperCase(c));
  695. boolean isUpperCaseAndPreviousIsLowerCase = (Character.isLowerCase(previousChar)) && (Character.isUpperCase(c));
  696. boolean previousIsWhitespace = Character.isWhitespace(previousChar);
  697. boolean lastOneIsNotUnderscore = (buf.length() > 0) && (buf.charAt(buf.length() - 1) != '_');
  698. boolean isNotUnderscore = c != '_';
  699. if ((lastOneIsNotUnderscore) && ((isUpperCaseAndPreviousIsLowerCase) || (previousIsWhitespace) || ((betweenUpperCases)
  700. && (containsLowerCase) && (isUpperCaseAndPreviousIsUpperCase)))) {
  701. buf.append("_");
  702. } else if (((separatorAfterDigit) && (Character.isDigit(previousChar))
  703. && (Character.isLetter(c))) || ((separatorBeforeDigit) && (Character
  704. .isDigit(c)) && (Character.isLetter(previousChar)))) {
  705. buf.append('_');
  706. }
  707. if ((shouldReplace(c)) && (lastOneIsNotUnderscore)) {
  708. buf.append('_');
  709. } else if ((!Character.isWhitespace(c)) && ((isNotUnderscore) || (lastOneIsNotUnderscore))) {
  710. buf.append(Character.toUpperCase(c));
  711. }
  712. previousChar = c;
  713. }
  714. if (Character.isWhitespace(previousChar)) {
  715. buf.append("_");
  716. }
  717. return buf.toString();
  718. }
  719. public static boolean containsLowerCase(String s) {
  720. for (char c : s.toCharArray()) {
  721. if (Character.isLowerCase(c)) {
  722. return true;
  723. }
  724. }
  725. return false;
  726. }
  727. private static boolean shouldReplace(char c) {
  728. return (c == '.') || (c == '_') || (c == '-');
  729. }
  730. private static String wordsToHyphenCase(String s) {
  731. StringBuilder buf = new StringBuilder();
  732. char lastChar = 'a';
  733. for (char c : s.toCharArray()) {
  734. if ((Character.isWhitespace(lastChar)) && (!Character.isWhitespace(c))
  735. && ('-' != c) && (buf.length() > 0)
  736. && (buf.charAt(buf.length() - 1) != '-')) {
  737. buf.append("-");
  738. }
  739. if ('_' == c) {
  740. buf.append('-');
  741. } else if ('.' == c) {
  742. buf.append('-');
  743. } else if (!Character.isWhitespace(c)) {
  744. buf.append(Character.toLowerCase(c));
  745. }
  746. lastChar = c;
  747. }
  748. if (Character.isWhitespace(lastChar)) {
  749. buf.append("-");
  750. }
  751. return buf.toString();
  752. }
  753. }