Skip to content

Instantly share code, notes, and snippets.

@dragon66
Created September 25, 2014 15:14
Show Gist options
  • Save dragon66/e9b8fb13c657e12b7145 to your computer and use it in GitHub Desktop.
Save dragon66/e9b8fb13c657e12b7145 to your computer and use it in GitHub Desktop.
Java ISO8601 Utility
/**
* Copyright (c) 2014 by Wen Yu.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Any modifications to this file must keep this entire header intact.
*/
package cafe.date;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
/**
* A wrapper for the Date class with information for TimeZone, Locale as well
* as a calendar associated with it
*
* @author Wen Yu, [email protected]
* @version 1.0 02/15/2013
*/
public class DateTime
{
private Date date;
private TimeZone timeZone;
private Locale locale;
private Calendar calendar;
public DateTime(Date date) {
this(date, TimeZone.getDefault(), Locale.getDefault());
}
public DateTime(Date date, TimeZone timeZone, Locale locale) {
this.date = date;
this.timeZone = timeZone;
this.locale = locale;
this.calendar = Calendar.getInstance(timeZone, locale);
calendar.setTime(date);
}
public DateTime(Date date, TimeZone timeZone) {
this(date, timeZone, Locale.getDefault());
}
public boolean after(DateTime that) {
return this.getUTCTimeInMillis() > that.getUTCTimeInMillis();
}
public boolean before(DateTime that) {
return this.getUTCTimeInMillis() < that.getUTCTimeInMillis();
}
/**
* Simple representation of the current date for the default TimeZone
* and Locale.
*
* @return a DateTime object for the default TimeZone and Locale.
*/
public static DateTime currentDate() {
TimeZone tz = TimeZone.getDefault();
Locale locale = Locale.getDefault();
return currentDate(tz, locale);
}
public static DateTime currentDate(TimeZone timeZone) {
Locale locale = Locale.getDefault();
return currentDate(timeZone, locale);
}
public static DateTime currentDate(TimeZone timeZone, Locale locale) {
Date date = new Date();
return new DateTime(date, timeZone, locale);
}
public static DateTime currentDateUTC() {
return currentDate(TimeZone.getTimeZone("UTC"));
}
public static DateTime currentDateUTC(Locale locale) {
return currentDate(TimeZone.getTimeZone("UTC"), locale);
}
public DateTime dateAfter(int years, int months) {
Calendar clone = (Calendar)calendar.clone();
clone.add(Calendar.YEAR, years);
clone.add(Calendar.MONTH, months);
return new DateTime(clone.getTime(), timeZone, locale);
}
public DateTime dateAfter(int years, int months, int days) {
Calendar clone = (Calendar)calendar.clone();
clone.add(Calendar.YEAR, years);
clone.add(Calendar.MONTH, months);
clone.add(Calendar.DAY_OF_MONTH, days);
return new DateTime(clone.getTime(), timeZone, locale);
}
public DateTime dateAfter(int years, int months, int days, int hours, int minutes, int seconds, int millis) {
Calendar clone = (Calendar)calendar.clone();
clone.add(Calendar.YEAR, years);
clone.add(Calendar.MONTH, months);
clone.add(Calendar.DAY_OF_MONTH, days);
clone.add(Calendar.HOUR, hours);
clone.add(Calendar.MINUTE, minutes);
clone.add(Calendar.SECOND, seconds);
clone.add(Calendar.MILLISECOND, millis);
return new DateTime(clone.getTime(), timeZone, locale);
}
public DateTime daysAfter(int days) {
return new DateTime(new Date(date.getTime() + 1000L*3600*24*days), timeZone, locale);
}
public boolean equals(Object that) {
if (!(that instanceof DateTime))
return false;
return this.getUTCTimeInMillis() == ((DateTime)that).getUTCTimeInMillis();
}
public String format(DateFormat df) {
return df.format(date);
}
public String format(String format) {
return format(format, Locale.getDefault());
}
public String format(String format, Locale locale) {
DateFormat df = new SimpleDateFormat(format, (locale == null)?Locale.getDefault():locale);
df.setTimeZone(timeZone);
String dateString = df.format(date);
return dateString;
}
/**
* Formats a DateTime to a ISO8601 string with a second fraction part of up to 3 digits.
*/
public String formatISO8601() {
return ISO8601DateUtils.formatISO8601(date, timeZone);
}
public Date getDate() {
return (Date)date.clone();
}
public int getDayOfMonth() {
return calendar.get(Calendar.DAY_OF_MONTH);
}
public int getDayOfWeek() {
return calendar.get(Calendar.DAY_OF_WEEK);
}
public int getMonth() {
return calendar.get(Calendar.MONTH);
}
public long getUTCTimeInMillis() {
long time = date.getTime();
int zoneOffset = timeZone.getOffset(time);
return time + zoneOffset;
}
public int getYear() {
return calendar.get(Calendar.YEAR);
}
public int hashCode() {
return Long.valueOf(getUTCTimeInMillis()).hashCode();
}
public DateTime hoursAfter(int hours) {
return new DateTime(new Date(date.getTime() + 1000L*3600*hours), timeZone, locale);
}
public DateTime monthsAfter(int months) {
Calendar clone = (Calendar)calendar.clone();
clone.add(Calendar.MONTH, months);
return new DateTime(clone.getTime(), timeZone, locale);
}
public String toString() {
DateFormat df = DateFormat.getInstance();
df.setTimeZone(timeZone);
return df.format(this.date) + " " + timeZone.getDisplayName();
}
public DateTime yearsAfter(int years) {
Calendar clone = (Calendar)calendar.clone();
clone.add(Calendar.YEAR, years);
return new DateTime(clone.getTime(), timeZone, locale);
}
}
/**
* Copyright (c) 2014 by Wen Yu.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Any modifications to this file must keep this entire header intact.
*/
package cafe.date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import cafe.date.DateTime;
import cafe.string.StringUtils;
/**
* http://www.w3.org/TR/NOTE-datetime
*
* The formats are as follows. Exactly the components shown here must be
* present, with exactly this punctuation. Note that the "T" appears literally
* in the string, to indicate the beginning of the time element, as specified in
* ISO 8601.
*
* Year:
* YYYY (eg 1997)
* Year and month:
* YYYY-MM (eg 1997-07)
* Complete date:
* YYYY-MM-DD (eg 1997-07-16)
* Complete date plus hours and minutes:
* YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
* Complete date plus hours, minutes and seconds:
* YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
* Complete date plus hours, minutes, seconds and a decimal fraction of a second
* YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
*
* where:
*
* YYYY = four-digit year
* MM = two-digit month (01=January, etc.)
* DD = two-digit day of month (01 through 31)
* hh = two digits of hour (00 through 23) (am/pm NOT allowed)
* mm = two digits of minute (00 through 59)
* ss = two digits of second (00 through 59)
* s = one or more digits representing a decimal fraction of a second
* TZD = time zone designator (Z or +hh:mm or -hh:mm)
*/
/**
* ISO 8601 date utilities.
*
* Supports up to 3 digits fraction of a second.
*
* @author Wen Yu, [email protected]
* @version 1.0 03/04/2013
*/
public class ISO8601DateUtils {
private ISO8601DateUtils() {}
/**
* Formats a DateTime to a ISO8601 string with a second fraction part of up to 3 digits.
*/
public static String formatISO8601(Date date, TimeZone timeZone) {
SimpleDateFormat df = null;
if (timeZone != null) {
df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.'SSSZ");
df.setTimeZone(timeZone);
String result = df.format(date);
if (result.endsWith("0000"))
return result.replaceAll("[+-]0000$", "Z");
return result.replaceAll("(\\d{2})(\\d{2})$", "$1:$2");
}
df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
return df.format(date);
}
/**
* Parses a ISO8601 string into a DateTime to retain time zone information.
*
* The pattern is dynamically created in accordance with the input date string.
* Time zone is optional.
*
* The fraction part of the second if exists is cut down to 3 digits, i.e to the
* precision of millisecond.
*/
public static DateTime parse(String input) throws ParseException {
TimeZone timeZone = null;
StringBuilder sb = new StringBuilder(30);
String[] dateParts = {"yyyy", "yyyy-MM", "yyyy-MM-dd"};
String[] timeParts = {"HH", "HH:mm", "HH:mm:ss"};
String[] inputs = input.split("-");
sb.append(dateParts[Math.min(inputs.length - 1, 2)]);
int timeIndex = input.indexOf("T");
// If we have time parts
if (timeIndex > 0)
{
input = input.replace("Z", "+00:00");
boolean hasTimeZone = false;
int timeZoneLen = 0;
String timeStr = input.substring(timeIndex);
// If we have time zone
//if (StringUtils.contains(timeStr, "[+-]\\d{2}:\\d{2}$"))
if (timeStr.indexOf("+") > 0 || timeStr.indexOf("-") > 0)
{
hasTimeZone = true;
timeZoneLen = 5;
timeZone = TimeZone.getTimeZone("GMT" + input.substring(input.length() - 6));
input = StringUtils.replaceLast(input, ":", "");
}
String[] timeInputs = input.split(":");
sb.append("'T'");
sb.append(timeParts[timeInputs.length - 1]);
int indexOfDot = input.indexOf(".");
if (indexOfDot > 0) {
sb.append("'.'");
int secondFractionLen = input.length() - indexOfDot - 1 - timeZoneLen;
// cut to 3 digits, we avoid round up which may cause problem in case of carrying
if (secondFractionLen > 3)
{
String secondFractionStr = input.substring(indexOfDot, indexOfDot + secondFractionLen + 1);
input = input.replace(secondFractionStr, input.substring(indexOfDot, indexOfDot + 4));
}
for (int j = secondFractionLen; j > 0; j--)
{
sb.append("S");
}
}
if (hasTimeZone)
sb.append("Z");
}
SimpleDateFormat df = new SimpleDateFormat(sb.toString());
return new DateTime(df.parse(input), timeZone);
}
public static String format(Date date, String format) {
SimpleDateFormat df = new SimpleDateFormat(format);
return df.format(date);
}
public static String format(Date date) {
return format(date, "yyyy-MM-dd'T'HH:mm:ss.SSS");
}
}
/**
* Copyright (c) 2014 by Wen Yu.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Any modifications to this file must keep this entire header intact.
*/
package cafe.string;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.regex.*;
/**
* String utility class
*
* @author Wen Yu, [email protected]
* @version 1.0 09/18/2012
*/
public class StringUtils
{
private static final char[] HEXES = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
/**
* Formats byte array.
*
* @param bytes an array of byte.
* @return a hex string representation of the byte array.
*/
public static String byteArrayToHexString(byte [] bytes) {
if ( bytes == null ) {
return null;
}
StringBuilder hex = new StringBuilder(5*bytes.length + 2);
hex.append("[");
if (bytes.length > 0)
{
for (byte b : bytes ) {
hex.append("0x").append(HEXES[(b & 0xf0) >> 4])
.append(HEXES[b & 0x0f]).append(",");
}
hex.deleteCharAt(hex.length()-1);
}
hex.append("]");
return hex.toString();
}
public static String byteToHexString(byte b) {
return String.format("0x%02X ", b);
}
/**
* Capitalizes the first character of the words in a string.
*
* @param s the input string
* @return a string with the first character of all words capitalized
*/
public static String capitalize(String s)
{
StringBuffer myStringBuffer = new StringBuffer();
Pattern p = Pattern.compile("\\b(\\w)(\\w*)");
Matcher m = p.matcher(s);
while (m.find()) {
if(!Character.isUpperCase(m.group().charAt(0)))
m.appendReplacement(myStringBuffer, m.group(1).toUpperCase()+"$2");
}
return m.appendTail(myStringBuffer).toString();
}
public static String capitalizeFully(String s)
{
return capitalize(s.toLowerCase());
}
public static String concat(Iterable<? extends CharSequence> strings, String delimiter)
{
int capacity = 0;
int delimLength = delimiter.length();
Iterator<? extends CharSequence> iter = strings.iterator();
while (iter.hasNext()) {
CharSequence next = iter.next();
if(!isNullOrEmpty(next))
capacity += next.length() + delimLength;
}
StringBuilder buffer = new StringBuilder(capacity);
iter = strings.iterator();
while (iter.hasNext()) {
CharSequence next = iter.next();
if(!isNullOrEmpty(next)) {
buffer.append(next);
buffer.append(delimiter);
}
}
int lastIndexOfDelimiter = buffer.lastIndexOf(delimiter);
buffer.delete(lastIndexOfDelimiter, buffer.length());
return buffer.toString();
}
public static String concat(String first, String second)
{
if(first == null) return second;
if(second == null) return first;
StringBuilder sb = new StringBuilder(first.length() + second.length());
sb.append(first);
sb.append(second);
return sb.toString();
}
public static String concat(String first, String... strings)
{
StringBuilder sb;
if(first != null) sb = new StringBuilder(first);
else sb = new StringBuilder();
for (String s: strings) {
if(!isNullOrEmpty(s))
sb.append(s);
}
return sb.toString();
}
public static <T extends CharSequence> String concat(T[] strings, String delimiter)
{
int capacity = 0;
int delimLength = delimiter.length();
for (T value : strings) {
if(!isNullOrEmpty(value))
capacity += value.length() + delimLength;
}
StringBuilder buffer = new StringBuilder(capacity);
for (T value : strings) {
if(!isNullOrEmpty(value)) {
buffer.append(value);
buffer.append(delimiter);
}
}
int lastIndexOfDelimiter = buffer.lastIndexOf(delimiter);
buffer.delete(lastIndexOfDelimiter, buffer.length());
return buffer.toString();
}
/**
* Regular expression version of the String contains method.
* If used with a match from start or match from end regular expression,
* it becomes the regular expression version of the {@link String#
* startsWith(String prefix)} or {@link String#endsWith(String suffix)}
* methods.
*
* @param input the input string
* @param regex the regular expression to which this string is to be matched
* @return true if a match is found, otherwise false
*/
public static boolean contains(String input, String regex)
{
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(input);
if (m.find()) {
return true;
}
return false;
}
/**
* From www.javapractices.com EscapeChars.java
*
* @param url URL string to be encoded
* @return a encoded URL string
*/
public static String encodeURL(String url)
{
String result = null;
try {
result = URLEncoder.encode(url, "UTF-8");
}
catch (UnsupportedEncodingException ex){
throw new RuntimeException("UTF-8 not supported", ex);
}
return result;
}
/**
* Escapes HTML reserved characters and other characters which might cause Cross Site Scripting
* (XSS) hacks
*
* The following table comes from www.javapractice.com EscapeChars.java
*
* <P>The following characters are replaced with corresponding HTML character entities:
*
* <table border='1' cellpadding='3' cellspacing='0'>
* <tr><th> Character </th><th>Replacement</th></tr>
* <tr><td> < </td><td> &lt; </td></tr>
* <tr><td> > </td><td> &gt; </td></tr>
* <tr><td> & </td><td> &amp; </td></tr>
* <tr><td> " </td><td> &quot;</td></tr>
* <tr><td> \t </td><td> &#009;</td></tr>
* <tr><td> ! </td><td> &#033;</td></tr>
* <tr><td> # </td><td> &#035;</td></tr>
* <tr><td> $ </td><td> &#036;</td></tr>
* <tr><td> % </td><td> &#037;</td></tr>
* <tr><td> ' </td><td> &#039;</td></tr>
* <tr><td> ( </td><td> &#040;</td></tr>
* <tr><td> ) </td><td> &#041;</td></tr>
* <tr><td> * </td><td> &#042;</td></tr>
* <tr><td> + </td><td> &#043; </td></tr>
* <tr><td> , </td><td> &#044; </td></tr>
* <tr><td> - </td><td> &#045; </td></tr>
* <tr><td> . </td><td> &#046; </td></tr>
* <tr><td> / </td><td> &#047; </td></tr>
* <tr><td> : </td><td> &#058;</td></tr>
* <tr><td> ; </td><td> &#059;</td></tr>
* <tr><td> = </td><td> &#061;</td></tr>
* <tr><td> ? </td><td> &#063;</td></tr>
* <tr><td> @ </td><td> &#064;</td></tr>
* <tr><td> [ </td><td> &#091;</td></tr>
* <tr><td> \ </td><td> &#092;</td></tr>
* <tr><td> ] </td><td> &#093;</td></tr>
* <tr><td> ^ </td><td> &#094;</td></tr>
* <tr><td> _ </td><td> &#095;</td></tr>
* <tr><td> ` </td><td> &#096;</td></tr>
* <tr><td> { </td><td> &#123;</td></tr>
* <tr><td> | </td><td> &#124;</td></tr>
* <tr><td> } </td><td> &#125;</td></tr>
* <tr><td> ~ </td><td> &#126;</td></tr>
* </table>
*
* @return a string with the specified characters replaced by HTML entities
*/
public static String escapeHTML(String input)
{
Iterator<Character> itr = stringIterator(input);
StringBuilder result = new StringBuilder();
while (itr.hasNext())
{
Character c = itr.next();
switch (c)
{
case '<':
result.append("&lt;");
break;
case '>':
result.append("&gt;");
break;
case '&':
result.append("&amp;");
break;
case '"':
result.append("&quot;");
break;
case '\t':
result.append("&#009;");
break;
case '!':
result.append("&#033;");
break;
case '#':
result.append("&#035;");
break;
case '$':
result.append("&#036;");
break;
case '%':
result.append("&#037;");
break;
case '\'':
result.append("&#039;");
break;
case '(':
result.append("&#040;");
break;
case ')':
result.append("&#041;");
break;
case '*':
result.append("&#042;");
break;
case '+':
result.append("&#043;");
break;
case ',':
result.append("&#044;");
break;
case '-':
result.append("&#045;");
break;
case '.':
result.append("&#046;");
break;
case '/':
result.append("&#047;");
break;
case ':':
result.append("&#058;");
break;
case ';':
result.append("&#059;");
break;
case '=':
result.append("&#061;");
break;
case '?':
result.append("&#063;");
break;
case '@':
result.append("&#064;");
break;
case '[':
result.append("&#091;");
break;
case '\\':
result.append("&#092;");
break;
case ']':
result.append("&#093;");
break;
case '^':
result.append("&#094;");
break;
case '_':
result.append("&#095;");
break;
case '`':
result.append("&#096;");
break;
case '{':
result.append("&#123;");
break;
case '|':
result.append("&#124;");
break;
case '}':
result.append("&#125;");
break;
case '~':
result.append("&#126;");
break;
default:
result.append(c);
}
}
return result.toString();
}
/**
* Replaces "&" with its entity "&amp;" to make it a valid HTML link
*
* @param queryString a URL string with a query string attached
* @return a valid URL string to be used as a link
*/
public static String escapeQueryStringAmp(String queryString)
{
return queryString.replace("&", "&amp;");
}
public static String escapeRegex(String input)
{
Iterator<Character> itr = stringIterator(input);
StringBuilder result = new StringBuilder();
while (itr.hasNext())
{
Character c = itr.next();
switch (c)
{
case '.':
case '^':
case '$':
case '*':
case '+':
case '?':
case '(':
case ')':
case '[':
case '{':
result.append("\\").append(c);
break;
case '\\':
result.append("\\\\");
break;
default:
result.append(c);
}
}
return result.toString();
}
public static String escapeXML(String input)
{
Iterator<Character> itr = stringIterator(input);
StringBuilder result = new StringBuilder();
while (itr.hasNext())
{
Character c = itr.next();
switch (c)
{
case '"':
result.append("&quot;");
break;
case '\'':
result.append("&apos;");
break;
case '<':
result.append("&lt;");
break;
case '>':
result.append("&gt;");
break;
case '&':
result.append("&amp;");
break;
default:
result.append(c);
}
}
return result.toString();
}
public static String intToHexString(int value) {
StringBuilder buffer = new StringBuilder(10);
buffer.append("0x");
buffer.append(HEXES[(value & 0x0000000F)]);
buffer.append(HEXES[(value & 0x000000F0) >>> 4]);
buffer.append(HEXES[(value & 0x00000F00) >>> 8]);
buffer.append(HEXES[(value & 0x0000F000) >>> 12]);
buffer.append(HEXES[(value & 0x000F0000) >>> 16]);
buffer.append(HEXES[(value & 0x00F00000) >>> 20]);
buffer.append(HEXES[(value & 0x0F000000) >>> 24]);
buffer.append(HEXES[(value & 0xF0000000) >>> 28]);
return buffer.toString();
}
public static String intToHexStringMM(int value) {
StringBuilder buffer = new StringBuilder(10);
buffer.append("0x");
buffer.append(HEXES[(value & 0xF0000000) >>> 28]);
buffer.append(HEXES[(value & 0x0F000000) >>> 24]);
buffer.append(HEXES[(value & 0x00F00000) >>> 20]);
buffer.append(HEXES[(value & 0x000F0000) >>> 16]);
buffer.append(HEXES[(value & 0x0000F000) >>> 12]);
buffer.append(HEXES[(value & 0x00000F00) >>> 8]);
buffer.append(HEXES[(value & 0x000000F0) >>> 4]);
buffer.append(HEXES[(value & 0x0000000F)]);
return buffer.toString();
}
/**
* Checks if a string is null, empty, or consists only of white spaces
*
* @param str the input CharSequence to check
* @return true if the input string is null, empty, or contains only white
* spaces, otherwise false
*/
public static boolean isNullOrEmpty(CharSequence str)
{
return ((str == null) || (str.length() == 0));
}
/**
* Formats TIFF long data field.
*
* @param data an array of int.
* @param unsigned true if the int value should be treated as unsigned,
* otherwise false
* @return a string representation of the int array.
*/
public static String longArrayToString(int[] data, boolean unsigned) {
StringBuilder longs = new StringBuilder();
longs.append("[");
for (int i=0; i<data.length; i++)
{
if(unsigned) {
// Convert it to unsigned integer
longs.append(data[i]&0xffffffffL);
} else {
longs.append(data[i]);
}
longs.append(",");
}
longs.deleteCharAt(longs.length()-1);
longs.append("]");
return longs.toString();
}
public static boolean parseBoolean(String s) {
return Boolean.parseBoolean(s);
}
public static byte parseByte(String s) {
return Byte.parseByte(s);
}
public static byte parseByte(String s, int radix) {
return Byte.parseByte(s, radix);
}
public static double parseDouble(String s) {
return Double.parseDouble(s);
}
public static float parseFloat(String s) {
return Float.parseFloat(s);
}
public static int parseInt(String s) {
return Integer.parseInt(s);
}
public static int parseInt(String s, int radix) {
return Integer.parseInt(s, radix);
}
public static long parseLong(String s) {
return Long.parseLong(s);
}
public static long parseLong(String s, int radix) {
return Long.parseLong(s, radix);
}
public static short parseShort(String s) {
return Short.parseShort(s);
}
public static short parseShort(String s, int radix) {
return Short.parseShort(s, radix);
}
public static String quoteRegexReplacement(String replacement)
{
return Matcher.quoteReplacement(replacement);
}
/**
* Formats TIFF rational data field.
*
* @param data an array of int.
* @param unsigned true if the int value should be treated as unsigned,
* otherwise false
* @return a string representation of the int array.
*/
public static String rationalArrayToString(int[] data, boolean unsigned)
{
if(data.length%2 != 0)
throw new IllegalArgumentException("Data length is odd number, expect even!");
StringBuilder rational = new StringBuilder();
rational.append("[");
for (int i=0; i<data.length; i+=2)
{
long numerator = data[i], denominator = data[i+1];
if (unsigned) {
// Converts it to unsigned integer
numerator = (data[i]&0xffffffffL);
denominator = (data[i+1]&0xffffffffL);
}
rational.append(numerator);
rational.append("/");
rational.append(denominator);
rational.append(",");
}
rational.deleteCharAt(rational.length()-1);
rational.append("]");
return rational.toString();
}
/**
* Replaces the last occurrence of the string represented by the regular expression
*
* @param input input string
* @param regex the regular expression to which this string is to be matched
* @param replacement the string to be substituted for the match
* @return the resulting String
*/
public static String replaceLast(String input, String regex, String replacement)
{
return input.replaceAll(regex+"(?!.*"+regex+")", replacement); // Using negative look ahead
}
public static String reverse(String s)
{
int i, len = s.length();
StringBuilder dest = new StringBuilder(len);
for (i = (len - 1); i >= 0; i--)
dest.append(s.charAt(i));
return dest.toString();
}
public static String reverse(String str, String delimiter)
{
if(isNullOrEmpty(delimiter)) {
return str;
}
StringBuilder sb = new StringBuilder(str.length());
reverseIt(str, delimiter, sb);
return sb.toString();
}
public static String reverse2(String str, String delimiter)
{
if(isNullOrEmpty(delimiter) || isNullOrEmpty(str) || (str.trim().length() == 0) || (str.indexOf(delimiter) < 0)) {
return str;
}
String escaptedDelimiter = escapeRegex(delimiter);
// Keep the trailing white spaces by setting limit to -1
String[] stringArray = str.split(escaptedDelimiter, -1);
StringBuilder sb = new StringBuilder(str.length() + delimiter.length());
for (int i = stringArray.length-1; i >= 0; i--)
{
sb.append(stringArray[i]).append(delimiter);
}
return sb.substring(0, sb.lastIndexOf(delimiter));
}
private static void reverseIt(String str, String delimiter, StringBuilder sb)
{
if(isNullOrEmpty(str) || (str.trim().length() == 0) || str.indexOf(delimiter) < 0) {
sb.append(str);
return;
}
// Recursion
reverseIt(str.substring(str.indexOf(delimiter)+delimiter.length()), delimiter, sb);
sb.append(delimiter);
sb.append(str.substring(0, str.indexOf(delimiter)));
}
public static String reverseWords(String s)
{
String[] stringArray = s.split("\\b");
StringBuilder sb = new StringBuilder(s.length());
for (int i = stringArray.length-1; i >= 0; i--)
{
sb.append(stringArray[i]);
}
return sb.toString();
}
/**
* Formats TIFF short data field.
*
* @param data an array of short.
* @param unsigned true if the short value should be treated as unsigned,
* otherwise false
* @return a string representation of the short array.
*/
public static String shortArrayToString(short[] data, boolean unsigned)
{
StringBuilder shorts = new StringBuilder();
shorts.append("[");
for (int i=0; i<data.length; i++)
{
if(unsigned) {
// Convert it to unsigned short
shorts.append(data[i]&0xffff);
} else {
shorts.append(data[i]);
}
shorts.append(",");
}
shorts.deleteCharAt(shorts.length()-1);
shorts.append("]");
return shorts.toString();
}
public static String shortToHexString(short value) {
StringBuilder buffer = new StringBuilder(6);
buffer.append("0x");
buffer.append(HEXES[(value & 0x000F)]);
buffer.append(HEXES[(value & 0x00F0) >>> 4]);
buffer.append(HEXES[(value & 0x0F00) >>> 8]);
buffer.append(HEXES[(value & 0xF000) >>> 12]);
return buffer.toString();
}
public static String shortToHexStringMM(short value) {
StringBuilder buffer = new StringBuilder(6);
buffer.append("0x");
buffer.append(HEXES[(value & 0xF000) >>> 12]);
buffer.append(HEXES[(value & 0x0F00) >>> 8]);
buffer.append(HEXES[(value & 0x00F0) >>> 4]);
buffer.append(HEXES[(value & 0x000F)]);
return buffer.toString();
}
/**
* Converts stack trace to string
*/
public static String stackTraceToString(Throwable e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
return sw.toString();
}
/**
* A read-only String iterator from stackoverflow.com
*
* @param string input string to be iterated
* @return an iterator for the input string
*/
public static Iterator<Character> stringIterator(final String string)
{
// Ensure the error is found as soon as possible.
if (string == null)
throw new NullPointerException();
return new Iterator<Character>() {
private int index = 0;
public boolean hasNext() {
return index < string.length();
}
public Character next() {
/*
* Throw NoSuchElementException as defined by the Iterator contract,
* not IndexOutOfBoundsException.
*/
if (!hasNext())
throw new NoSuchElementException();
return string.charAt(index++);
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
private StringUtils(){} // Prevents instantiation
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment