1 package be
.nikiroo
.utils
;
4 import java
.awt
.image
.BufferedImage
;
5 import java
.io
.ByteArrayInputStream
;
6 import java
.io
.ByteArrayOutputStream
;
8 import java
.io
.IOException
;
9 import java
.io
.InputStream
;
10 import java
.security
.MessageDigest
;
11 import java
.security
.NoSuchAlgorithmException
;
12 import java
.text
.Normalizer
;
13 import java
.text
.Normalizer
.Form
;
14 import java
.text
.ParseException
;
15 import java
.text
.SimpleDateFormat
;
16 import java
.util
.Date
;
17 import java
.util
.Scanner
;
18 import java
.util
.regex
.Pattern
;
20 import javax
.imageio
.ImageIO
;
22 import org
.unbescape
.html
.HtmlEscape
;
23 import org
.unbescape
.html
.HtmlEscapeLevel
;
24 import org
.unbescape
.html
.HtmlEscapeType
;
27 * This class offer some utilities based around {@link String}s.
31 public class StringUtils
{
33 * This enum type will decide the alignment of a {@link String} when padding
34 * is applied or if there is enough horizontal space for it to be aligned.
36 public enum Alignment
{
37 /** Aligned at left. */
41 /** Aligned at right. */
45 static private Pattern marks
= Pattern
46 .compile("[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+");
49 * Fix the size of the given {@link String} either with space-padding or by
53 * the {@link String} to fix
55 * the size of the resulting {@link String} or -1 for a noop
57 * @return the resulting {@link String} of size <i>size</i>
59 static public String
padString(String text
, int width
) {
60 return padString(text
, width
, true, Alignment
.Beginning
);
64 * Fix the size of the given {@link String} either with space-padding or by
65 * optionally shortening it.
68 * the {@link String} to fix
70 * the size of the resulting {@link String} if the text fits or
71 * if cut is TRUE or -1 for a noop
73 * cut the {@link String} shorter if needed
75 * align the {@link String} in this position if we have enough
78 * @return the resulting {@link String} of size <i>size</i> minimum
80 static public String
padString(String text
, int width
, boolean cut
,
87 int diff
= width
- text
.length();
91 text
= text
.substring(0, width
);
92 } else if (diff
> 0) {
93 if (diff
< 2 && align
!= Alignment
.End
)
94 align
= Alignment
.Beginning
;
98 text
= text
+ new String(new char[diff
]).replace('\0', ' ');
101 text
= new String(new char[diff
]).replace('\0', ' ') + text
;
105 int pad1
= (diff
) / 2;
106 int pad2
= (diff
+ 1) / 2;
107 text
= new String(new char[pad1
]).replace('\0', ' ') + text
108 + new String(new char[pad2
]).replace('\0', ' ');
118 * Sanitise the given input to make it more Terminal-friendly by removing
119 * combining characters.
122 * the input to sanitise
123 * @param allowUnicode
124 * allow Unicode or only allow ASCII Latin characters
126 * @return the sanitised {@link String}
128 static public String
sanitize(String input
, boolean allowUnicode
) {
129 return sanitize(input
, allowUnicode
, !allowUnicode
);
133 * Sanitise the given input to make it more Terminal-friendly by removing
134 * combining characters.
137 * the input to sanitise
138 * @param allowUnicode
139 * allow Unicode or only allow ASCII Latin characters
140 * @param removeAllAccents
141 * TRUE to replace all accentuated characters by their non
142 * accentuated counter-parts
144 * @return the sanitised {@link String}
146 static public String
sanitize(String input
, boolean allowUnicode
,
147 boolean removeAllAccents
) {
149 if (removeAllAccents
) {
150 input
= Normalizer
.normalize(input
, Form
.NFKD
);
151 input
= marks
.matcher(input
).replaceAll("");
154 input
= Normalizer
.normalize(input
, Form
.NFKC
);
157 StringBuilder builder
= new StringBuilder();
158 for (int index
= 0; index
< input
.length(); index
++) {
159 char car
= input
.charAt(index
);
160 // displayable chars in ASCII are in the range 32<->255,
162 if (car
>= 32 && car
<= 255 && car
!= 127) {
166 input
= builder
.toString();
173 * Convert between time in milliseconds to {@link String} in a "static" way
174 * (to exchange data over the wire, for instance).
177 * the time in milliseconds
179 * @return the time as a {@link String}
181 static public String
fromTime(long time
) {
182 SimpleDateFormat sdf
= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
183 return sdf
.format(new Date(time
));
187 * Convert between time as a {@link String} to milliseconds in a "static"
188 * way (to exchange data over the wire, for instance).
191 * the time as a {@link String}
193 * @return the time in milliseconds
195 static public long toTime(String displayTime
) {
196 SimpleDateFormat sdf
= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
198 return sdf
.parse(displayTime
).getTime();
199 } catch (ParseException e
) {
205 * Convert the given {@link Image} object into a Base64 representation of
206 * the same {@link Image}. object.
209 * the {@link Image} object to convert
211 * @return the Base64 representation
213 * @throws IOException
214 * in case of IO error
216 static public String
fromImage(BufferedImage image
) throws IOException
{
217 return fromImage(image
, null);
221 * Convert the given {@link Image} object into a Base64 representation of
222 * the same {@link Image}. object.
225 * the {@link Image} object to convert
227 * the image format to use to serialise it (default is PNG)
229 * @return the Base64 representation
231 * @throws IOException
232 * in case of IO error
234 static public String
fromImage(BufferedImage image
, String format
)
236 if (format
== null) {
240 String imageString
= null;
241 ByteArrayOutputStream out
= new ByteArrayOutputStream();
243 ImageIO
.write(image
, format
, out
);
244 byte[] imageBytes
= out
.toByteArray();
246 imageString
= new String(Base64
.encodeBytes(imageBytes
));
254 * Convert the given image into a Base64 representation of the same
258 * the image to convert
260 * @return the Base64 representation
262 * @throws IOException
263 * in case of IO error
265 static public String
fromStream(InputStream in
) throws IOException
{
266 String fileString
= null;
267 ByteArrayOutputStream out
= new ByteArrayOutputStream();
269 byte[] buf
= new byte[8192];
272 while ((c
= in
.read(buf
, 0, buf
.length
)) > 0) {
273 out
.write(buf
, 0, c
);
278 fileString
= new String(Base64
.encodeBytes(out
.toByteArray()));
285 * Convert the given Base64 representation of an image into an {@link Image}
289 * the {@link Image} in Base64 format
291 * @return the {@link Image} object
293 * @throws IOException
294 * in case of IO error
296 static public BufferedImage
toImage(String b64data
) throws IOException
{
297 ByteArrayInputStream in
= new ByteArrayInputStream(
298 Base64
.decode(b64data
));
299 return IOUtils
.toImage(in
);
303 * Return a hash of the given {@link String}.
310 static public String
getHash(String input
) {
312 MessageDigest md
= MessageDigest
.getInstance("MD5");
313 md
.update(input
.getBytes());
314 byte byteData
[] = md
.digest();
316 StringBuffer hexString
= new StringBuffer();
317 for (int i
= 0; i
< byteData
.length
; i
++) {
318 String hex
= Integer
.toHexString(0xff & byteData
[i
]);
319 if (hex
.length() == 1)
320 hexString
.append('0');
321 hexString
.append(hex
);
324 return hexString
.toString();
325 } catch (NoSuchAlgorithmException e
) {
331 * Remove the HTML content from the given input, and un-html-ize the rest.
334 * the HTML-encoded content
336 * @return the HTML-free equivalent content
338 public static String
unhtml(String html
) {
339 StringBuilder builder
= new StringBuilder();
342 for (char car
: html
.toCharArray()) {
345 } else if (car
== '>') {
347 } else if (inTag
<= 0) {
352 char nbsp
= ' '; // non-breakable space (a special char)
354 return HtmlEscape
.unescapeHtml(builder
.toString()).replace(nbsp
, space
);
358 * Escape the given {@link String} so it can be used in XML, as content.
361 * the input {@link String}
363 * @return the escaped {@link String}
365 public static String
xmlEscape(String input
) {
370 return HtmlEscape
.escapeHtml(input
,
371 HtmlEscapeType
.HTML4_NAMED_REFERENCES_DEFAULT_TO_HEXA
,
372 HtmlEscapeLevel
.LEVEL_1_ONLY_MARKUP_SIGNIFICANT
);
376 * Escape the given {@link String} so it can be used in XML, as text content
377 * inside double-quotes.
380 * the input {@link String}
382 * @return the escaped {@link String}
384 public static String
xmlEscapeQuote(String input
) {
389 return HtmlEscape
.escapeHtml(input
,
390 HtmlEscapeType
.HTML4_NAMED_REFERENCES_DEFAULT_TO_HEXA
,
391 HtmlEscapeLevel
.LEVEL_1_ONLY_MARKUP_SIGNIFICANT
);
394 public static String
zip64(String data
) {
396 return Base64
.encodeBytes(data
.getBytes(), Base64
.GZIP
);
397 } catch (IOException e
) {
403 public static String
unzip64(String data
) throws IOException
{
404 ByteArrayInputStream in
= new ByteArrayInputStream(Base64
.decode(data
,
407 Scanner scan
= new Scanner(in
);
408 scan
.useDelimiter("\\A");