PageRenderTime 58ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/plugins/org.python.pydev.core/src/org/python/pydev/core/docutils/StringUtils.java

https://github.com/rdenadai/Pydev
Java | 1289 lines | 991 code | 146 blank | 152 comment | 224 complexity | e1eb2e5fc789d257d6d8fe7e3518d6b8 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, EPL-1.0, GPL-2.0, BSD-3-Clause
  1. /**
  2. * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
  3. * Licensed under the terms of the Eclipse Public License (EPL).
  4. * Please see the license.txt included with this distribution for details.
  5. * Any modifications to this file must keep this entire header intact.
  6. */
  7. /*
  8. * Created on 03/09/2005
  9. */
  10. package org.python.pydev.core.docutils;
  11. import java.io.Reader;
  12. import java.io.StringReader;
  13. import java.io.UnsupportedEncodingException;
  14. import java.math.BigInteger;
  15. import java.net.URLEncoder;
  16. import java.security.MessageDigest;
  17. import java.util.ArrayList;
  18. import java.util.Collection;
  19. import java.util.HashMap;
  20. import java.util.Iterator;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.NoSuchElementException;
  24. import javax.swing.text.Document;
  25. import javax.swing.text.EditorKit;
  26. import javax.swing.text.html.HTMLEditorKit;
  27. import org.eclipse.core.runtime.Assert;
  28. import org.python.pydev.core.ObjectsPool;
  29. import org.python.pydev.core.Tuple;
  30. import org.python.pydev.core.cache.Cache;
  31. import org.python.pydev.core.cache.LRUCache;
  32. import org.python.pydev.core.log.Log;
  33. import org.python.pydev.core.structure.FastStringBuffer;
  34. public final class StringUtils {
  35. /**
  36. * @author fabioz
  37. *
  38. */
  39. private static final class IterLines implements Iterator<String> {
  40. private final String string;
  41. private final int len;
  42. private int i;
  43. private boolean calculatedNext;
  44. private boolean hasNext;
  45. private String next;
  46. private IterLines(String string) {
  47. this.string = string;
  48. this.len = string.length();
  49. }
  50. public boolean hasNext() {
  51. if(!calculatedNext){
  52. calculatedNext = true;
  53. hasNext = calculateNext();
  54. }
  55. return hasNext;
  56. }
  57. private boolean calculateNext() {
  58. next = null;
  59. char c;
  60. int start = i;
  61. for (;i < len; i++) {
  62. c = string.charAt(i);
  63. if (c == '\r') {
  64. if (i < len - 1 && string.charAt(i + 1) == '\n') {
  65. i++;
  66. }
  67. i++;
  68. next = string.substring(start, i);
  69. return true;
  70. }
  71. if (c == '\n') {
  72. i++;
  73. next = string.substring(start, i);
  74. return true;
  75. }
  76. }
  77. if (start != i) {
  78. next = string.substring(start, i);
  79. i++;
  80. return true;
  81. }
  82. return false;
  83. }
  84. public String next() {
  85. if(!hasNext()){
  86. throw new NoSuchElementException();
  87. }
  88. String n = next;
  89. calculatedNext = false;
  90. next = null;
  91. return n;
  92. }
  93. public void remove() {
  94. throw new UnsupportedOperationException();
  95. }
  96. }
  97. private StringUtils(){
  98. }
  99. public static final Object EMPTY = "";
  100. /**
  101. * Formats a string, replacing %s with the arguments passed.
  102. *
  103. * %% is also changed to %.
  104. *
  105. * If % is followed by any other char, the % and the next char are ignored.
  106. *
  107. * @param str string to be formatted
  108. * @param args arguments passed
  109. * @return a string with the %s replaced by the arguments passed
  110. */
  111. public static String format(String str, Object... args) {
  112. int length = str.length();
  113. FastStringBuffer buffer = new FastStringBuffer(length+(16*args.length));
  114. int j = 0;
  115. int i = 0;
  116. int start = 0;
  117. for (; i < length; i++) {
  118. char c = str.charAt(i);
  119. if (c == '%') {
  120. if(i + 1 < length){
  121. if(i > start){
  122. buffer.append(str.substring(start, i));
  123. }
  124. char nextC = str.charAt(i + 1);
  125. switch (nextC) {
  126. case 's':
  127. buffer.appendObject(args[j]);
  128. j++;
  129. break;
  130. case '%':
  131. buffer.append('%');
  132. j++;
  133. break;
  134. }
  135. i++;
  136. start = i+1;
  137. }
  138. }
  139. }
  140. if(i > start){
  141. buffer.append(str.substring(start, i));
  142. }
  143. return buffer.toString();
  144. }
  145. /**
  146. * Counts the number of %s in the string
  147. *
  148. * @param str the string to be analyzide
  149. * @return the number of %s in the string
  150. */
  151. public static int countPercS(String str) {
  152. int j = 0;
  153. int len = str.length();
  154. for (int i = 0; i < len; i++) {
  155. char c = str.charAt(i);
  156. if (c == '%' && i + 1 < len) {
  157. char nextC = str.charAt(i + 1);
  158. if (nextC == 's') {
  159. j++;
  160. i++;
  161. }
  162. }
  163. }
  164. return j;
  165. }
  166. /**
  167. * Removes whitespaces and tabs at the end of the string.
  168. */
  169. public static String rightTrim(String input) {
  170. int len = input.length();
  171. int st = 0;
  172. int off = 0;
  173. char[] val = input.toCharArray();
  174. while ((st < len) && (val[off + len - 1] <= ' ')) {
  175. len--;
  176. }
  177. return input.substring(0, len);
  178. }
  179. /**
  180. * Removes whitespaces and tabs at the beggining of the string.
  181. */
  182. public static String leftTrim(String input) {
  183. int len = input.length();
  184. int off = 0;
  185. char[] val = input.toCharArray();
  186. while ((off < len) && (val[off] <= ' ')) {
  187. off++;
  188. }
  189. return input.substring(off, len);
  190. }
  191. /**
  192. * Given a string remove all from the rightmost '.' onwards.
  193. *
  194. * E.g.: bbb.t would return bbb
  195. *
  196. * If it has no '.', returns the original string unchanged.
  197. */
  198. public static String stripExtension(String input) {
  199. return stripFromRigthCharOnwards(input, '.');
  200. }
  201. public static int rFind(String input, char ch){
  202. int len = input.length();
  203. int st = 0;
  204. int off = 0;
  205. char[] val = input.toCharArray();
  206. while ((st < len) && (val[off + len - 1] != ch)) {
  207. len--;
  208. }
  209. len--;
  210. return len;
  211. }
  212. private static String stripFromRigthCharOnwards(String input, char ch) {
  213. int len = rFind(input, ch);
  214. if(len == -1){
  215. return input;
  216. }
  217. return input.substring(0, len);
  218. }
  219. public static String stripFromLastSlash(String input) {
  220. return stripFromRigthCharOnwards(input, '/');
  221. }
  222. /**
  223. * Removes the occurrences of the passed char in the beggining of the string.
  224. */
  225. public static String rightTrim(String input, char charToTrim) {
  226. int len = input.length();
  227. int st = 0;
  228. int off = 0;
  229. char[] val = input.toCharArray();
  230. while ((st < len) && (val[off + len - 1] == charToTrim)) {
  231. len--;
  232. }
  233. return input.substring(0, len);
  234. }
  235. /**
  236. * Removes the occurrences of the passed char in the start and end of the string.
  237. */
  238. public static String leftAndRightTrim(String input, char charToTrim) {
  239. return rightTrim(leftTrim(input, charToTrim), charToTrim);
  240. }
  241. /**
  242. * Removes the occurrences of the passed char in the end of the string.
  243. */
  244. public static String leftTrim(String input, char charToTrim) {
  245. int len = input.length();
  246. int off = 0;
  247. char[] val = input.toCharArray();
  248. while ((off < len) && (val[off] == charToTrim)) {
  249. off++;
  250. }
  251. return input.substring(off, len);
  252. }
  253. /**
  254. * Changes all backward slashes (\) for forward slashes (/)
  255. *
  256. * @return the replaced string
  257. */
  258. public static String replaceAllSlashes(String string) {
  259. int len = string.length();
  260. char c = 0;
  261. for (int i = 0; i < len; i++) {
  262. c = string.charAt(i);
  263. if (c == '\\') { // only do some processing if there is a
  264. // backward slash
  265. char[] ds = string.toCharArray();
  266. ds[i] = '/';
  267. for (int j = i; j < len; j++) {
  268. if (ds[j] == '\\') {
  269. ds[j] = '/';
  270. }
  271. }
  272. return new String(ds);
  273. }
  274. }
  275. return string;
  276. }
  277. /**
  278. * Splits the given string in a list where each element is a line.
  279. *
  280. * @param string string to be split.
  281. * @return list of strings where each string is a line.
  282. *
  283. * @note the new line characters are also added to the returned string.
  284. */
  285. public static List<String> splitInLines(String string) {
  286. ArrayList<String> ret = new ArrayList<String>();
  287. int len = string.length();
  288. char c;
  289. FastStringBuffer buf = new FastStringBuffer();
  290. for (int i = 0; i < len; i++) {
  291. c = string.charAt(i);
  292. buf.append(c);
  293. if (c == '\r') {
  294. if (i < len - 1 && string.charAt(i + 1) == '\n') {
  295. i++;
  296. buf.append('\n');
  297. }
  298. ret.add(buf.toString());
  299. buf.clear();
  300. }
  301. if (c == '\n') {
  302. ret.add(buf.toString());
  303. buf.clear();
  304. }
  305. }
  306. if (buf.length() != 0) {
  307. ret.add(buf.toString());
  308. }
  309. return ret;
  310. }
  311. /**
  312. * Splits the given string in a list where each element is a line.
  313. *
  314. * @param string string to be split.
  315. * @return list of strings where each string is a line.
  316. *
  317. * @note the new line characters are also added to the returned string.
  318. *
  319. * IMPORTANT: The line returned will be a substring of the initial line, so, it's recommended that a copy
  320. * is created if it should be kept in memory (otherwise the full initial string will also be kept in memory).
  321. */
  322. public static Iterable<String> iterLines(final String string) {
  323. return new Iterable<String>() {
  324. public Iterator<String> iterator() {
  325. return new IterLines(string);
  326. }
  327. };
  328. }
  329. public static String replaceAll(String string, String replace, String with) {
  330. FastStringBuffer ret = new FastStringBuffer(string, 16);
  331. return ret.replaceAll(replace, with).toString();
  332. }
  333. /**
  334. * Formats a docstring to be shown and adds the indentation passed to all the docstring lines but the 1st one.
  335. */
  336. public static String fixWhitespaceColumnsToLeftFromDocstring(String docString, String indentationToAdd) {
  337. FastStringBuffer buf = new FastStringBuffer();
  338. List<String> splitted = splitInLines(docString);
  339. for(int i=0;i<splitted.size();i++){
  340. String initialString = splitted.get(i);
  341. if(i == 0){
  342. buf.append(initialString);//first is unchanged
  343. }else{
  344. String string = StringUtils.leftTrim(initialString);
  345. buf.append(indentationToAdd);
  346. if(string.length() > 0){
  347. buf.append(string);
  348. }else{
  349. int length = initialString.length();
  350. if(length > 0){
  351. char c;
  352. if(length > 1){
  353. //check 2 chars
  354. c = initialString.charAt(length-2);
  355. if(c == '\n' || c == '\r'){
  356. buf.append(c);
  357. }
  358. }
  359. c = initialString.charAt(length-1);
  360. if(c == '\n' || c == '\r'){
  361. buf.append(c);
  362. }
  363. }
  364. }
  365. }
  366. }
  367. //last line
  368. if(buf.length() > 0){
  369. char c = buf.lastChar();
  370. if(c == '\r' || c == '\n'){
  371. buf.append(indentationToAdd);
  372. }
  373. }
  374. return buf.toString();
  375. }
  376. public static String removeWhitespaceColumnsToLeft(String hoverInfo) {
  377. FastStringBuffer buf = new FastStringBuffer();
  378. int firstCharPosition = Integer.MAX_VALUE;
  379. List<String> splitted = splitInLines(hoverInfo);
  380. for(String line:splitted){
  381. if(line.trim().length() > 0){
  382. int found = PySelection.getFirstCharPosition(line);
  383. firstCharPosition = Math.min(found, firstCharPosition);
  384. }
  385. }
  386. if(firstCharPosition != Integer.MAX_VALUE){
  387. for(String line:splitted){
  388. if(line.length() > firstCharPosition){
  389. buf.append(line.substring(firstCharPosition));
  390. }
  391. }
  392. return buf.toString();
  393. }else{
  394. return hoverInfo;//return initial
  395. }
  396. }
  397. public static String removeWhitespaceColumnsToLeftAndApplyIndent(
  398. String code, String indent, boolean indentCommentLinesAt0Pos) {
  399. FastStringBuffer buf = new FastStringBuffer();
  400. int firstCharPosition = Integer.MAX_VALUE;
  401. List<String> splitted = splitInLines(code);
  402. for(String line:splitted){
  403. if(indentCommentLinesAt0Pos || !line.startsWith("#")){
  404. if(line.trim().length() > 0){
  405. int found = PySelection.getFirstCharPosition(line);
  406. firstCharPosition = Math.min(found, firstCharPosition);
  407. }
  408. }
  409. }
  410. if(firstCharPosition != Integer.MAX_VALUE){
  411. for(String line:splitted){
  412. if(indentCommentLinesAt0Pos || !line.startsWith("#")){
  413. buf.append(indent);
  414. if(line.length() > firstCharPosition){
  415. buf.append(line.substring(firstCharPosition));
  416. }else{
  417. buf.append(line);
  418. }
  419. }else{
  420. buf.append(line);
  421. }
  422. }
  423. return buf.toString();
  424. }else{
  425. return code;//return initial
  426. }
  427. }
  428. /**
  429. * Given some html, extracts its text.
  430. */
  431. public static String extractTextFromHTML(String html) {
  432. try {
  433. EditorKit kit = new HTMLEditorKit();
  434. Document doc = kit.createDefaultDocument();
  435. // The Document class does not yet handle charset's properly.
  436. doc.putProperty("IgnoreCharsetDirective", Boolean.TRUE);
  437. // Create a reader on the HTML content.
  438. Reader rd = new StringReader(html);
  439. // Parse the HTML.
  440. kit.read(rd, doc, 0);
  441. // The HTML text is now stored in the document
  442. return doc.getText(0, doc.getLength());
  443. } catch (Exception e) {
  444. }
  445. return "";
  446. }
  447. /**
  448. * Splits the passed string based on the toSplit string.
  449. */
  450. public static List<String> split(final String string, final char toSplit, int maxPartsToSplit) {
  451. Assert.isTrue(maxPartsToSplit > 0);
  452. ArrayList<String> ret = new ArrayList<String>();
  453. int len = string.length();
  454. int last = 0;
  455. char c = 0;
  456. for (int i = 0; i < len; i++) {
  457. c = string.charAt(i);
  458. if(c == toSplit){
  459. if(last != i){
  460. if(ret.size() == maxPartsToSplit-1){
  461. ret.add(string.substring(last, string.length()));
  462. return ret;
  463. }else{
  464. ret.add(string.substring(last, i));
  465. }
  466. }
  467. while(c == toSplit && i < len-1){
  468. i++;
  469. c = string.charAt(i);
  470. }
  471. last = i;
  472. }
  473. }
  474. if(c != toSplit){
  475. if(last == 0 && len > 0){
  476. ret.add(string); //it is equal to the original (no char to split)
  477. }else if(last < len){
  478. ret.add(string.substring(last, len));
  479. }
  480. }
  481. return ret;
  482. }
  483. /**
  484. * Splits the passed string based on the toSplit string.
  485. */
  486. public static List<String> split(final String string, final String toSplit) {
  487. if(toSplit.length() == 1){
  488. return split(string, toSplit.charAt(0));
  489. }
  490. ArrayList<String> ret = new ArrayList<String>();
  491. if(toSplit.length() == 0){
  492. ret.add(string);
  493. return ret;
  494. }
  495. int len = string.length();
  496. int last = 0;
  497. char c = 0;
  498. for (int i = 0; i < len; i++) {
  499. c = string.charAt(i);
  500. if(c == toSplit.charAt(0) && matches(string, toSplit, i)){
  501. if(last != i){
  502. ret.add(string.substring(last, i));
  503. }
  504. last = i+toSplit.length();
  505. i+= toSplit.length() -1;
  506. }
  507. }
  508. if(last < len){
  509. ret.add(string.substring(last, len));
  510. }
  511. return ret;
  512. }
  513. private static boolean matches(String string, String toSplit, int i) {
  514. if(string.length()-i >= toSplit.length()){
  515. for(int j=0;j<toSplit.length();j++){
  516. if(string.charAt(i+j) != toSplit.charAt(j)){
  517. return false;
  518. }
  519. }
  520. return true;
  521. }
  522. return false;
  523. }
  524. /**
  525. * Splits some string given some char (that char will not appear in the returned strings)
  526. * Empty strings are also never added.
  527. */
  528. public static void splitWithIntern(String string, char toSplit, Collection<String> addTo) {
  529. synchronized (ObjectsPool.lock) {
  530. int len = string.length();
  531. int last = 0;
  532. char c = 0;
  533. for (int i = 0; i < len; i++) {
  534. c = string.charAt(i);
  535. if(c == toSplit){
  536. if(last != i){
  537. addTo.add(ObjectsPool.internUnsynched(string.substring(last, i)));
  538. }
  539. while(c == toSplit && i < len-1){
  540. i++;
  541. c = string.charAt(i);
  542. }
  543. last = i;
  544. }
  545. }
  546. if(c != toSplit){
  547. if(last == 0 && len > 0){
  548. addTo.add(ObjectsPool.internUnsynched(string)); //it is equal to the original (no char to split)
  549. }else if(last < len){
  550. addTo.add(ObjectsPool.internUnsynched(string.substring(last, len)));
  551. }
  552. }
  553. }
  554. }
  555. /**
  556. * Splits some string given some char (that char will not appear in the returned strings)
  557. * Empty strings are also never added.
  558. */
  559. public static List<String> split(String string, char toSplit) {
  560. ArrayList<String> ret = new ArrayList<String>();
  561. int len = string.length();
  562. int last = 0;
  563. char c = 0;
  564. for (int i = 0; i < len; i++) {
  565. c = string.charAt(i);
  566. if(c == toSplit){
  567. if(last != i){
  568. ret.add(string.substring(last, i));
  569. }
  570. while(c == toSplit && i < len-1){
  571. i++;
  572. c = string.charAt(i);
  573. }
  574. last = i;
  575. }
  576. }
  577. if(c != toSplit){
  578. if(last == 0 && len > 0){
  579. ret.add(string); //it is equal to the original (no char to split)
  580. }else if(last < len){
  581. ret.add(string.substring(last, len));
  582. }
  583. }
  584. return ret;
  585. }
  586. /**
  587. * Splits some string given many chars
  588. */
  589. public static List<String> split(String string, char ... toSplit) {
  590. ArrayList<String> ret = new ArrayList<String>();
  591. int len = string.length();
  592. int last = 0;
  593. char c = 0;
  594. for (int i = 0; i < len; i++) {
  595. c = string.charAt(i);
  596. if(contains(c, toSplit)){
  597. if(last != i){
  598. ret.add(string.substring(last, i));
  599. }
  600. while(contains(c, toSplit) && i < len-1){
  601. i++;
  602. c = string.charAt(i);
  603. }
  604. last = i;
  605. }
  606. }
  607. if(!contains(c, toSplit)){
  608. if(last == 0 && len > 0){
  609. ret.add(string); //it is equal to the original (no dots)
  610. }else if(last < len){
  611. ret.add(string.substring(last, len));
  612. }
  613. }
  614. return ret;
  615. }
  616. public static List<String> splitAndRemoveEmptyNotTrimmed(String string, char c){
  617. List<String> split = split(string, c);
  618. for(int i=split.size()-1;i>=0;i--){
  619. if(split.get(i).length() == 0){
  620. split.remove(i);
  621. }
  622. }
  623. return split;
  624. }
  625. public static List<String> splitAndRemoveEmptyTrimmed(String string, char c){
  626. List<String> split = split(string, c);
  627. for(int i=split.size()-1;i>=0;i--){
  628. if(split.get(i).trim().length() == 0){
  629. split.remove(i);
  630. }
  631. }
  632. return split;
  633. }
  634. private static boolean contains(char c, char[] toSplit){
  635. for(char ch:toSplit){
  636. if(c == ch){
  637. return true;
  638. }
  639. }
  640. return false;
  641. }
  642. /**
  643. * Splits some string given some char in 2 parts. If the separator is not found,
  644. * everything is put in the 1st part.
  645. */
  646. public static Tuple<String, String> splitOnFirst(String fullRep, char toSplit) {
  647. int i = fullRep.indexOf(toSplit);
  648. if(i != -1){
  649. return new Tuple<String, String>(
  650. fullRep.substring(0, i),
  651. fullRep.substring(i+1));
  652. }else{
  653. return new Tuple<String, String>(fullRep,"");
  654. }
  655. }
  656. /**
  657. * Splits some string given some char in 2 parts. If the separator is not found,
  658. * everything is put in the 1st part.
  659. */
  660. public static Tuple<String, String> splitOnFirst(String fullRep, String toSplit) {
  661. int i = fullRep.indexOf(toSplit);
  662. if(i != -1){
  663. return new Tuple<String, String>(
  664. fullRep.substring(0, i),
  665. fullRep.substring(i+toSplit.length()));
  666. }else{
  667. return new Tuple<String, String>(fullRep,"");
  668. }
  669. }
  670. /**
  671. * Splits the string as would string.split("\\."), but without yielding empty strings
  672. */
  673. public static List<String> dotSplit(String string) {
  674. return splitAndRemoveEmptyTrimmed(string, '.');
  675. }
  676. public static String join(String delimiter, Object ... splitted) {
  677. String [] newSplitted = new String[splitted.length];
  678. for(int i=0;i<splitted.length;i++){
  679. Object s = splitted[i];
  680. if(s == null){
  681. newSplitted[i] = "null";
  682. }else{
  683. newSplitted[i] = s.toString();
  684. }
  685. }
  686. return join(delimiter, newSplitted);
  687. }
  688. /**
  689. * Same as Python join: Go through all the paths in the string and join them with the passed delimiter.
  690. */
  691. public static String join(String delimiter, String[] splitted) {
  692. FastStringBuffer buf = new FastStringBuffer(splitted.length*100);
  693. boolean first = true;
  694. for (String string : splitted) {
  695. if(!first){
  696. buf.append(delimiter);
  697. }else{
  698. first = false;
  699. }
  700. buf.append(string);
  701. }
  702. return buf.toString();
  703. }
  704. /**
  705. * Same as Python join: Go through all the paths in the string and join them with the passed delimiter,
  706. * but start at the passed initial location in the splitted array.
  707. */
  708. public static String join(String delimiter, String[] splitted, int startAtSegment, int endAtSegment) {
  709. FastStringBuffer buf = new FastStringBuffer(splitted.length*100);
  710. boolean first = true;
  711. for (int i=startAtSegment;i<splitted.length && i < endAtSegment;i++) {
  712. if(!first){
  713. buf.append(delimiter);
  714. }else{
  715. first = false;
  716. }
  717. buf.append(splitted[i]);
  718. }
  719. return buf.toString();
  720. }
  721. /**
  722. * Same as Python join: Go through all the paths in the string and join them with the passed delimiter.
  723. */
  724. public static String join(String delimiter, List<String> splitted) {
  725. FastStringBuffer buf = new FastStringBuffer(splitted.size()*100);
  726. boolean first = true;
  727. for (String string : splitted) {
  728. if(!first){
  729. buf.append(delimiter);
  730. }else{
  731. first = false;
  732. }
  733. buf.append(string);
  734. }
  735. return buf.toString();
  736. }
  737. /**
  738. * Adds a char to an array of chars and returns the new array.
  739. *
  740. * @param c The chars to where the new char should be appended
  741. * @param toAdd the char to be added
  742. * @return a new array with the passed char appended.
  743. */
  744. public static char[] addChar(char[] c, char toAdd) {
  745. char[] c1 = new char[c.length + 1];
  746. System.arraycopy(c, 0, c1, 0, c.length);
  747. c1[c.length] = toAdd;
  748. return c1;
  749. }
  750. public static String[] addString(String[] c, String toAdd) {
  751. String[] c1 = new String[c.length + 1];
  752. System.arraycopy(c, 0, c1, 0, c.length);
  753. c1[c.length] = toAdd;
  754. return c1;
  755. }
  756. public static String replaceNewLines(String message, String string) {
  757. message = message.replaceAll("\r\n", string);
  758. message = message.replaceAll("\r", string);
  759. message = message.replaceAll("\n", string);
  760. return message;
  761. }
  762. public static String removeNewLineChars(String message) {
  763. return message.replaceAll("\r","").replaceAll("\n","");
  764. }
  765. private static final int STATE_LOWER = 0;
  766. private static final int STATE_UPPER = 1;
  767. private static final int STATE_NUMBER = 2;
  768. public static String asStyleLowercaseUnderscores(String string) {
  769. FastStringBuffer buf = new FastStringBuffer(string.length()*2);
  770. char[] charArray = string.toCharArray();
  771. int lastState = 0;
  772. for(char c:charArray){
  773. if(Character.isUpperCase(c)){
  774. if(lastState != STATE_UPPER){
  775. if(buf.length() > 0 && buf.lastChar() != '_'){
  776. buf.append('_');
  777. }
  778. }
  779. buf.append(Character.toLowerCase(c));
  780. lastState = STATE_UPPER;
  781. }else if(Character.isDigit(c)){
  782. if(lastState != STATE_NUMBER){
  783. if(buf.length() > 0 && buf.lastChar() != '_'){
  784. buf.append('_');
  785. }
  786. }
  787. buf.append(c);
  788. lastState = STATE_NUMBER;
  789. }else{
  790. buf.append(c);
  791. lastState = STATE_LOWER;
  792. }
  793. }
  794. return buf.toString();
  795. }
  796. public static boolean isAllUpper(String string) {
  797. for(char c:string.toCharArray()){
  798. if(Character.isLetter(c) && !Character.isUpperCase(c)){
  799. return false;
  800. }
  801. }
  802. return true;
  803. }
  804. public static String asStyleCamelCaseFirstLower(String string) {
  805. if(isAllUpper(string)){
  806. string = string.toLowerCase();
  807. }
  808. FastStringBuffer buf = new FastStringBuffer(string.length());
  809. char[] charArray = string.toCharArray();
  810. boolean first = true;
  811. int nextUpper = 0;
  812. for(char c:charArray){
  813. if(first){
  814. if(c == '_'){
  815. //underscores at the start
  816. buf.append(c);
  817. continue;
  818. }
  819. buf.append(Character.toLowerCase(c));
  820. first = false;
  821. }else{
  822. if(c=='_'){
  823. nextUpper += 1;
  824. continue;
  825. }
  826. if(nextUpper > 0){
  827. c = Character.toUpperCase(c);
  828. nextUpper = 0;
  829. }
  830. buf.append(c);
  831. }
  832. }
  833. if(nextUpper > 0){
  834. //underscores at the end
  835. buf.appendN('_', nextUpper);
  836. }
  837. return buf.toString();
  838. }
  839. public static String asStyleCamelCaseFirstUpper(String string) {
  840. string = asStyleCamelCaseFirstLower(string);
  841. if(string.length() > 0){
  842. return Character.toUpperCase(string.charAt(0)) + string.substring(1);
  843. }
  844. return string;
  845. }
  846. public static boolean endsWith(FastStringBuffer str, char c) {
  847. if(str.length() == 0){
  848. return false;
  849. }
  850. if(str.charAt(str.length()-1) == c){
  851. return true;
  852. }
  853. return false;
  854. }
  855. public static boolean endsWith(String str, char c) {
  856. if(str.length() == 0){
  857. return false;
  858. }
  859. if(str.charAt(str.length()-1) == c){
  860. return true;
  861. }
  862. return false;
  863. }
  864. public static boolean endsWith(StringBuffer str, char c) {
  865. if(str.length() == 0){
  866. return false;
  867. }
  868. if(str.charAt(str.length()-1) == c){
  869. return true;
  870. }
  871. return false;
  872. }
  873. /**
  874. * Tests whether each character in the given
  875. * string is a letter.
  876. *
  877. * @param str
  878. * @return <code>true</code> if the given string is a word
  879. */
  880. public static boolean isWord(String str) {
  881. if (str == null || str.length() == 0)
  882. return false;
  883. for (int i= 0; i < str.length(); i++) {
  884. if (!Character.isJavaIdentifierPart(str.charAt(i)))
  885. return false;
  886. }
  887. return true;
  888. }
  889. /**
  890. * An array of Python pairs of characters that you will find in any Python code.
  891. *
  892. * Currently, the set contains:
  893. * <ul>
  894. * <ol>left and right brackets: [, ]</ol>
  895. * <ol>right and right parentheses: (, )
  896. * </ul>
  897. */
  898. public static final char[] BRACKETS = { '{', '}', '(', ')', '[', ']' };
  899. public static final char[] CLOSING_BRACKETS = { '}', ')', ']' };
  900. public static char getPeer(char c){
  901. switch(c){
  902. case '{':return '}';
  903. case '}':return '{';
  904. case '(':return ')';
  905. case ')':return '(';
  906. case '[':return ']';
  907. case ']':return '[';
  908. }
  909. throw new NoPeerAvailableException("Unable to find peer for :"+c);
  910. }
  911. public static String getWithClosedPeer(char c){
  912. switch(c){
  913. case '{':return "{}";
  914. case '(':return "()";
  915. case '[':return "[]";
  916. case '\'':return "''";
  917. case '"':return "\"\"";
  918. }
  919. throw new NoPeerAvailableException("Unable to find peer for :"+c);
  920. }
  921. public static boolean isOpeningPeer(char lastChar) {
  922. return lastChar == '(' || lastChar == '[' || lastChar == '{';
  923. }
  924. public static boolean isClosingPeer(char lastChar) {
  925. return lastChar == ')' || lastChar == ']' || lastChar == '}';
  926. }
  927. public static boolean hasOpeningBracket(String trimmedLine) {
  928. return trimmedLine.indexOf('{') != -1 || trimmedLine.indexOf('(') != -1 || trimmedLine.indexOf('[') != -1;
  929. }
  930. public static boolean hasClosingBracket(String trimmedLine) {
  931. return trimmedLine.indexOf('}') != -1 || trimmedLine.indexOf(')') != -1 || trimmedLine.indexOf(']') != -1;
  932. }
  933. public static boolean hasUnbalancedClosingPeers(String line) {
  934. Map<Character, Integer> stack = new HashMap<Character, Integer>();
  935. for(int i=0;i<line.length();i++){
  936. char c = line.charAt(i);
  937. switch(c){
  938. case '(':
  939. case '{':
  940. case '[':
  941. Integer iStack = stack.get(c);
  942. if(iStack == null){
  943. iStack = 0;
  944. }
  945. iStack++;
  946. stack.put(c, iStack);
  947. break;
  948. case ')':
  949. case '}':
  950. case ']':
  951. char peer = StringUtils.getPeer((char)c);
  952. iStack = stack.get(peer);
  953. if(iStack == null){
  954. iStack = 0;
  955. }
  956. iStack--;
  957. stack.put(peer, iStack);
  958. break;
  959. }
  960. }
  961. for(int i:stack.values()){
  962. if(i < 0){
  963. return true;
  964. }
  965. }
  966. return false;
  967. }
  968. /**
  969. * Small cache to hold strings only with spaces (so that each width has a created string).
  970. */
  971. private static Cache<Integer, String> widthToSpaceString = new LRUCache<Integer, String>(8);
  972. /**
  973. * Creates a string of spaces of the designated length.
  974. * @param width number of spaces you want to create a string of
  975. * @return the created string
  976. */
  977. public static String createSpaceString(int width) {
  978. String existing = StringUtils.widthToSpaceString.getObj(width);
  979. if(existing != null){
  980. return existing;
  981. }
  982. FastStringBuffer buf = new FastStringBuffer(width);
  983. buf.appendN(' ', width);
  984. String newStr = buf.toString();
  985. StringUtils.widthToSpaceString.add(width, newStr);
  986. return newStr;
  987. }
  988. public static int count(String name, char c) {
  989. int count=0;
  990. int len = name.length();
  991. for(int i=0;i<len;i++){
  992. if(name.charAt(i) == c){
  993. count++;
  994. }
  995. }
  996. return count;
  997. }
  998. public static String urlEncodeKeyValuePair(String key, String value) {
  999. String result = null;
  1000. try {
  1001. result = URLEncoder.encode(key, "UTF-8") + "=" + URLEncoder.encode(value, "UTF-8");
  1002. } catch (UnsupportedEncodingException e) {
  1003. Log.log(e);
  1004. }
  1005. return result;
  1006. }
  1007. public static boolean containsWhitespace(String name) {
  1008. for(int i=0;i<name.length();i++){
  1009. if(Character.isWhitespace(name.charAt(i))){
  1010. return true;
  1011. }
  1012. }
  1013. return false;
  1014. }
  1015. /**
  1016. * //Python 3.0 can use unicode identifiers. So, the letter construct deals with that...
  1017. * TOKEN : * Python identifiers *
  1018. * {
  1019. * < NAME: <LETTER> ( <LETTER> | <DIGIT>)* >
  1020. * |
  1021. * < #LETTER:
  1022. * [
  1023. * "a"-"z",
  1024. * "A"-"Z",
  1025. * "_",
  1026. * "\u0080"-"\uffff" //Anything more than 128 is considered valid (unicode range)
  1027. *
  1028. * ]
  1029. * >
  1030. * }
  1031. * @param param
  1032. * @return
  1033. */
  1034. public static boolean isPythonIdentifier(String param) {
  1035. if(param.length() == 0){
  1036. return false;
  1037. }
  1038. char c = param.charAt(0);
  1039. if(!Character.isLetter(c) && c != '_' && c <= 128){
  1040. return false;
  1041. }
  1042. for(int i=1;i<param.length();i++){
  1043. c = param.charAt(i);
  1044. if((!Character.isLetter(c) && !Character.isDigit(c) && c != '_') && (c <= 128)){
  1045. return false;
  1046. }
  1047. }
  1048. return true;
  1049. }
  1050. public static String getWithFirstUpper(String creationStr) {
  1051. if(creationStr.length() == 0){
  1052. return creationStr;
  1053. }
  1054. char upperCase = Character.toUpperCase(creationStr.charAt(0));
  1055. return upperCase+creationStr.substring(1);
  1056. }
  1057. public static String indentTo(String source, String indent) {
  1058. return indentTo(source, indent, true);
  1059. }
  1060. public static String indentTo(String source, String indent, boolean indentFirstLine) {
  1061. if(indent == null || indent.length() == 0){
  1062. return source;
  1063. }
  1064. List<String> splitInLines = splitInLines(source);
  1065. FastStringBuffer buf = new FastStringBuffer(source.length() + (splitInLines.size()* indent.length())+2);
  1066. for(int i=0;i<splitInLines.size();i++){
  1067. String line = splitInLines.get(i);
  1068. if(indentFirstLine || i > 0){
  1069. buf.append(indent);
  1070. }
  1071. buf.append(line);
  1072. }
  1073. return buf.toString();
  1074. }
  1075. private static final Object md5CacheLock = new Object();
  1076. private static final LRUCache<String, String> md5Cache = new LRUCache<String, String>(1000);
  1077. public static String md5(String str) {
  1078. synchronized (md5CacheLock) {
  1079. String obj = md5Cache.getObj(str);
  1080. if(obj != null){
  1081. return obj;
  1082. }
  1083. try {
  1084. byte[] bytes = str.getBytes("UTF-8");
  1085. MessageDigest md = MessageDigest.getInstance("MD5");
  1086. //MAX_RADIX because we'll generate the shorted string possible... (while still
  1087. //using only numbers 0-9 and letters a-z)
  1088. String ret = new BigInteger(1, md.digest(bytes)).toString(Character.MAX_RADIX).toLowerCase();
  1089. md5Cache.add(str, ret);
  1090. return ret;
  1091. } catch (Exception e) {
  1092. throw new RuntimeException(e);
  1093. }
  1094. }
  1095. }
  1096. /**
  1097. * @return the number of line breaks in the passed string.
  1098. */
  1099. public static int countLineBreaks(String replacementString) {
  1100. int lineBreaks = 0;
  1101. int ignoreNextNAt = -1;
  1102. //we may have line breaks with \r\n, or only \n or \r
  1103. for (int i = 0; i < replacementString.length(); i++) {
  1104. char c = replacementString.charAt(i);
  1105. if(c == '\r'){
  1106. lineBreaks++;
  1107. ignoreNextNAt = i + 1;
  1108. }else if(c == '\n'){
  1109. if(ignoreNextNAt != i){
  1110. lineBreaks++;
  1111. }
  1112. }
  1113. }
  1114. return lineBreaks;
  1115. }
  1116. }