/*
* The MIT License (MIT)
*
* Copyright (c) 2007-2015 Broad Institute
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.broad.igv.util;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
/**
* Created by IntelliJ IDEA.
* User: jrobinso
* Date: Oct 30, 2009
* Time: 1:51:36 AM
* To change this template use File | Settings | File Templates.
*/
public class StringUtils {
private static Map<String, String> internedStrings = new WeakHashMap<String, String>();
/**
* Creates or retrieves an interned copy of {@code string}. This way,
* we only keep one reference to strings of the same value.
* Backed by a WeakHashMap
*
* @param string
* @return
*/
public static String intern(String string) {
if (!internedStrings.containsKey(string)) {
internedStrings.put(string, string);
}
return internedStrings.get(string);
}
public static List<String> breakQuotedString(String string, char splitToken) {
if(string == null) return null;
ArrayList<String> strings = new ArrayList<String >();
if (string.length() == 0) {
return strings;
}
char[] characters = string.toCharArray();
char c;
boolean isQuoted = false;
StringBuffer buff = new StringBuffer(100);
for (int i = 0; i < characters.length; i++) {
c = characters[i];
if (isQuoted) {
if (c == '"') {
isQuoted = false;
}
buff.append(c);
} else if (c == '"') {
isQuoted = true;
buff.append(c);
} else {
if (c == splitToken) {
strings.add(buff.toString().trim());
buff.setLength(0);
} else {
buff.append(c);
}
}
}
if (buff.length() > 0) {
strings.add(buff.toString().trim());
}
return strings;
}
/**
* Return a possibly shortened representation of the input string
*/
public static String checkLength(String string, int maxLength) {
if (string.length() <= maxLength) {
return string;
}
int nDots = maxLength > 10 ? 3 : (maxLength > 5 ? 2 : 1);
int m = (Math.max(1, (maxLength - nDots) / 2));
StringBuffer newString = new StringBuffer(maxLength);
newString.append(string.substring(0, m));
for (int i = 0; i < nDots; i++) {
newString.append('.');
}
newString.append(string.substring(string.length() - m));
return newString.toString();
}
/**
* Covert a genotype string to a 8 byte integer representation
* <p/>
* example
* String genotype = "AC";
* short genoShort = genoToShort(genotype);
* <p/>
* char allel1 = (char) ((genoShort >>> 8) & 0xFF);
* char allel2 = (char) ((genoShort >>> 0) & 0xFF);
* <p/>
* System.out.println("Allele1: " + allel1);
* System.out.println("Allele2: " + allel2);
*
* @param genotype
* @return
*/
public static short genoToShort(String genotype) {
byte[] bytes = genotype.getBytes();
return (short) ((bytes[0] & 0xff) << 8 | (bytes[1] & 0xff));
}
public static String readString(ByteBuffer byteBuffer) throws IOException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
byte b = -1;
while ((b = byteBuffer.get()) != 0) {
bytes.write(b);
}
return new String(bytes.toByteArray());
}
/**
* Decode according to UTF-8. In the extremely unlikely
* event that we are running on a platform which does not
* support UTF-8 (it's part of the Java spec), a runtime
* exception is thrown
*
* @param s
* @return
*/
public static String decodeURL(String s) {
if (s == null) {
return null;
}
try {
return URLDecoder.decode(s, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
/**
* Encode according to UTF-8. We encode
* spaces as "%20" rather than "+", seems
* to work better with others.
* @param s
* @return
*/
public static String encodeURL(String s) {
if (s == null) {
return null;
}
try {
s = URLEncoder.encode(s, "UTF-8");
s = s.replace("+", "%20");
return s;
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
/**
* Attempts to encode only the query portion of a URL,
* ignoring delimiter characters. If it looks like it's already
* URL-encoded, does nothing
* @param url
* @return
*/
public static URL encodeURLQueryString(URL url) throws MalformedURLException{
String[] parts = url.toExternalForm().split("\\?", 2);
//If there are percent signs we assume it's already url encoded
if (parts.length > 1 && !parts[1].contains("%")) {
String queryPart = parts[1];
String[] params = queryPart.split("&");
String[] encParms = new String[params.length];
int ii = 0;
for (String kv : params) {
String[] kvs = kv.split("\\=", 2);
String encString = StringUtils.encodeURL(kvs[0]);
if(kvs.length == 2){
encString = String.format("%s=%s", encString, StringUtils.encodeURL(kvs[1]));
}
encParms[ii++] = encString;
}
String encQuery = StringUtils.join(encParms, "&");
String newPath = parts[0] + "?" + encQuery;
url = new URL(newPath);
}
return url;
}
/**
* Copy a text string to the clipboard
*
* @param text
*/
public static void copyTextToClipboard(String text) {
StringSelection stringSelection = new StringSelection(text);
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(stringSelection, null);
}
/**
* Converts an input string, of any case, into a series
* of capitalized words.
* toCapWords("BOB") -> "Bob"
* toCapWords("bOb is MY FRiend") -> "Bob Is My Friend"
*
* @param text
* @return
*/
public static String capWords(String text) {
String res = "";
boolean capNext = true;
String s;
for (char c : text.toLowerCase().toCharArray()) {
s = Character.toString(c);
if (capNext) {
s = s.toUpperCase();
}
res += s;
capNext = " ".equals(s);
}
return res;
}
public static String join(List list, String separator) {
return join(list.toArray(), separator);
}
/**
* Join the objects in {@code array} with the given {@code separator}
* Useful for making a comma separated list, or URL query string
* @param array
* @param separator
* @return
*/
public static String join(Object[] array, String separator) {
int num = array.length;
if(num == 0) return "";
String out = array[0].toString();
for(int ii=1; ii < num; ii++) {
out += (separator + array[ii].toString());
}
return out;
}
/**
* This must exist in the jdk ?
*
* @param string
* @return
*/
public static int countChar(String string, char c) {
int cnt = 0;
for (int i = 0; i < string.length(); i++) {
if (c == string.charAt(i)) {
cnt++;
}
}
return cnt;
}
/**
* Strips quotation marks from string. Quotes can be single or double, but must match each other.
*
* @param fileString
* @return
*/
public static String stripQuotes(String fileString) {
if ((fileString.startsWith("\"") && fileString.endsWith("\"")) ||
(fileString.startsWith("'") && fileString.endsWith("'"))) {
fileString = fileString.substring(1, fileString.length() - 1);
}
return fileString;
}
}