I am trying to modify a config file in Java using Properties.
I read, write and modify the lines successfully using Properties.store, load and setProperty, but I noticed that after doing such operation the file is overwritten and thus I loose al the lines in the config file that are not key-value pairs. Namely, I loose the comments.
Is there a way to keep such lines using java.util?
Placing a prefix in each line is not a problem. I know how to do it 'manually' reading line by line; I'am asking instead for an alternative
I don't think it is possible. Note that properties also don't promise that the ordering will be the same from load() to store(), or from one store() to another. If it is possible, the javadoc for Properties will tell you how.
import java.io.*;
import java.util.*;
/**
* The CommentedProperties class is an extension of java.util.Properties
* to allow retention of comment lines and blank (whitespace only) lines
* in the properties file.
*
* Written for Java version 1.4
*/
public class CommentedProperties extends java.util.Properties {
/**
* Use a Vector to keep a copy of lines that are a comment or 'blank'
*/
public Vector lineData = new Vector(0, 1);
/**
* Use a Vector to keep a copy of lines containing a key, i.e. they are a property.
*/
public Vector keyData = new Vector(0, 1);
/**
* Load properties from the specified InputStream.
* Overload the load method in Properties so we can keep comment and blank lines.
* #param inStream The InputStream to read.
*/
public void load(InputStream inStream) throws IOException
{
// The spec says that the file must be encoded using ISO-8859-1.
BufferedReader reader =
new BufferedReader(new InputStreamReader(inStream, "ISO-8859-1"));
String line;
while ((line = reader.readLine()) != null) {
char c = 0;
int pos = 0;
// Leading whitespaces must be deleted first.
while ( pos < line.length()
&& Character.isWhitespace(c = line.charAt(pos))) {
pos++;
}
// If empty line or begins with a comment character, save this line
// in lineData and save a "" in keyData.
if ( (line.length() - pos) == 0
|| line.charAt(pos) == '#' || line.charAt(pos) == '!') {
lineData.add(line);
keyData.add("");
continue;
}
// The characters up to the next Whitespace, ':', or '='
// describe the key. But look for escape sequences.
// Try to short-circuit when there is no escape char.
int start = pos;
boolean needsEscape = line.indexOf('\\', pos) != -1;
StringBuffer key = needsEscape ? new StringBuffer() : null;
while ( pos < line.length()
&& ! Character.isWhitespace(c = line.charAt(pos++))
&& c != '=' && c != ':') {
if (needsEscape && c == '\\') {
if (pos == line.length()) {
// The line continues on the next line. If there
// is no next line, just treat it as a key with an
// empty value.
line = reader.readLine();
if (line == null)
line = "";
pos = 0;
while ( pos < line.length()
&& Character.isWhitespace(c = line.charAt(pos)))
pos++;
} else {
c = line.charAt(pos++);
switch (c) {
case 'n':
key.append('\n');
break;
case 't':
key.append('\t');
break;
case 'r':
key.append('\r');
break;
case 'u':
if (pos + 4 <= line.length()) {
char uni = (char) Integer.parseInt
(line.substring(pos, pos + 4), 16);
key.append(uni);
pos += 4;
} // else throw exception?
break;
default:
key.append(c);
break;
}
}
} else if (needsEscape)
key.append(c);
}
boolean isDelim = (c == ':' || c == '=');
String keyString;
if (needsEscape)
keyString = key.toString();
else if (isDelim || Character.isWhitespace(c))
keyString = line.substring(start, pos - 1);
else
keyString = line.substring(start, pos);
while ( pos < line.length()
&& Character.isWhitespace(c = line.charAt(pos)))
pos++;
if (! isDelim && (c == ':' || c == '=')) {
pos++;
while ( pos < line.length()
&& Character.isWhitespace(c = line.charAt(pos)))
pos++;
}
// Short-circuit if no escape chars found.
if (!needsEscape) {
put(keyString, line.substring(pos));
// Save a "" in lineData and save this
// keyString in keyData.
lineData.add("");
keyData.add(keyString);
continue;
}
// Escape char found so iterate through the rest of the line.
StringBuffer element = new StringBuffer(line.length() - pos);
while (pos < line.length()) {
c = line.charAt(pos++);
if (c == '\\') {
if (pos == line.length()) {
// The line continues on the next line.
line = reader.readLine();
// We might have seen a backslash at the end of
// the file. The JDK ignores the backslash in
// this case, so we follow for compatibility.
if (line == null)
break;
pos = 0;
while ( pos < line.length()
&& Character.isWhitespace(c = line.charAt(pos)))
pos++;
element.ensureCapacity(line.length() - pos +
element.length());
} else {
c = line.charAt(pos++);
switch (c) {
case 'n':
element.append('\n');
break;
case 't':
element.append('\t');
break;
case 'r':
element.append('\r');
break;
case 'u':
if (pos + 4 <= line.length()) {
char uni = (char) Integer.parseInt
(line.substring(pos, pos + 4), 16);
element.append(uni);
pos += 4;
} // else throw exception?
break;
default:
element.append(c);
break;
}
}
} else
element.append(c);
}
put(keyString, element.toString());
// Save a "" in lineData and save this
// keyString in keyData.
lineData.add("");
keyData.add(keyString);
}
}
/**
* Write the properties to the specified OutputStream.
*
* Overloads the store method in Properties so we can put back comment
* and blank lines.
*
* #param out The OutputStream to write to.
* #param header Ignored, here for compatability w/ Properties.
*
* #exception IOException
*/
public void store(OutputStream out, String header) throws IOException
{
// The spec says that the file must be encoded using ISO-8859-1.
PrintWriter writer
= new PrintWriter(new OutputStreamWriter(out, "ISO-8859-1"));
// We ignore the header, because if we prepend a commented header
// then read it back in it is now a comment, which will be saved
// and then when we write again we would prepend Another header...
String line;
String key;
StringBuffer s = new StringBuffer ();
for (int i=0; i<lineData.size(); i++) {
line = (String) lineData.get(i);
key = (String) keyData.get(i);
if (key.length() > 0) { // This is a 'property' line, so rebuild it
formatForOutput (key, s, true);
s.append ('=');
formatForOutput ((String) get(key), s, false);
writer.println (s);
} else { // was a blank or comment line, so just restore it
writer.println (line);
}
}
writer.flush ();
}
/**
* Need this method from Properties because original code has StringBuilder,
* which is an element of Java 1.5, used StringBuffer instead (because
* this code was written for Java 1.4)
*
* #param str - the string to format
* #param buffer - buffer to hold the string
* #param key - true if str the key is formatted, false if the value is formatted
*/
private void formatForOutput(String str, StringBuffer buffer, boolean key)
{
if (key) {
buffer.setLength(0);
buffer.ensureCapacity(str.length());
} else
buffer.ensureCapacity(buffer.length() + str.length());
boolean head = true;
int size = str.length();
for (int i = 0; i < size; i++) {
char c = str.charAt(i);
switch (c) {
case '\n':
buffer.append("\\n");
break;
case '\r':
buffer.append("\\r");
break;
case '\t':
buffer.append("\\t");
break;
case ' ':
buffer.append(head ? "\\ " : " ");
break;
case '\\':
case '!':
case '#':
case '=':
case ':':
buffer.append('\\').append(c);
break;
default:
if (c < ' ' || c > '~') {
String hex = Integer.toHexString(c);
buffer.append("\\u0000".substring(0, 6 - hex.length()));
buffer.append(hex);
} else
buffer.append(c);
}
if (c != ' ')
head = key;
}
}
/**
* Add a Property to the end of the CommentedProperties.
*
* #param keyString The Property key.
* #param value The value of this Property.
*/
public void add(String keyString, String value)
{
put(keyString, value);
lineData.add("");
keyData.add(keyString);
}
/**
* Add a comment or blank line or comment to the end of the CommentedProperties.
*
* #param line The string to add to the end, make sure this is a comment
* or a 'whitespace' line.
*/
public void addLine(String line)
{
lineData.add(line);
keyData.add("");
}
}
Related
Using iText 7.1.3 and trying to add a SVG file into PdfDocument gives an output where texts with length 1 are not rendered. I found where it might be the problem.
I please the iText team members to check it.
try {
SvgConverter.drawOnCanvas(svgUrl.openStream(), pdfCanvas_, imageLlx, imageLly);
} catch (IOException e) {
e.printStackTrace();
}
Debugger callings:
processText:255, DefaultSvgProcessor (com.itextpdf.svg.processors.impl)
visit:212, DefaultSvgProcessor (com.itextpdf.svg.processors.impl)
visit:204, DefaultSvgProcessor (com.itextpdf.svg.processors.impl)
visit:204, DefaultSvgProcessor (com.itextpdf.svg.processors.impl)
executeDepthFirstTraversal:153, DefaultSvgProcessor (com.itextpdf.svg.processors.impl)
process:106, DefaultSvgProcessor (com.itextpdf.svg.processors.impl)
process:768, SvgConverter (com.itextpdf.svg.converter)
convertToXObject:555, SvgConverter (com.itextpdf.svg.converter)
convertToXObject:590, SvgConverter (com.itextpdf.svg.converter)
drawOnCanvas:380, SvgConverter (com.itextpdf.svg.converter)
In function processText, in the line for Trim trailing whitespace
trimmedText = SvgTextUtil.trimTrailingWhitespace("A");
for the trimmedText = A (length = 1) returns empty String
/**
* Process the text contained in the text-node
*
* #param textNode node containing text to process
*/
private void processText(ITextNode textNode) {
ISvgNodeRenderer parentRenderer = this.processorState.top();
if (parentRenderer instanceof TextSvgNodeRenderer) {
// when svg is parsed by jsoup it leaves all whitespace in text element as is. Meaning that
// tab/space indented xml files will retain their tabs and spaces.
// The following regex replaces all whitespace with a single space.
//TODO(RND-906) evaluate regex and trim methods
String trimmedText = textNode.wholeText().replaceAll("\\s+", " ");
//Trim leading whitespace
trimmedText = SvgTextUtil.trimLeadingWhitespace(trimmedText);
//Trim trailing whitespace
trimmedText = SvgTextUtil.trimTrailingWhitespace(trimmedText);
parentRenderer.setAttribute(SvgConstants.Attributes.TEXT_CONTENT, trimmedText);
}
}
There indeed is a bug in the trimTrailingWhitespace you pointed out
public static String trimTrailingWhitespace(String toTrim) {
if(toTrim == null){
return "";
}
int end = toTrim.length();
if (end > 0) {
int current = end - 1;
while (current > 0) {
char currentChar = toTrim.charAt(current);
if (Character.isWhitespace(currentChar) && !(currentChar == '\n' || currentChar == '\r')) {
//if the character is whitespace and not a newline, increase current
current--;
} else {
break;
}
}
if(current == 0){
return "";
}else {
return toTrim.substring(0, current + 1);
}
}else{
return toTrim;
}
}
As the comment //if the character is whitespace and not a newline, increase current followed by current--; already indicates, this method is a copy of trimLeadingWhitespace (where the line after the identical comment indeed increases current) modified to work at the other end of the String parameter. Unfortunately, though, the modification was incorrect: If the string has a non-whitespace character at position 0 and thereafter only whitespaces, it erroneously is considered empty.
The fix would be to replace
while (current > 0)
by
while (current >= 0)
and
if(current == 0)
by
if(current < 0)
With that fix the
if (end > 0) {
[...]
}else{
return toTrim;
}
frame around [...] furthermore becomes unnecessary. And the while loop could more compactly have been formulated as a for loop, e.g. like this:
public static String trimTrailingWhitespace(String toTrim) {
if (toTrim == null) {
return "";
}
int current = toTrim.length() - 1;
for ( ; current >= 0; current--) {
char currentChar = toTrim.charAt(current);
if (!(Character.isWhitespace(currentChar) && !(currentChar == '\n' || currentChar == '\r'))) {
break;
}
}
return current < 0 ? "" : toTrim.substring(0, current + 1);
}
I have a String like
value 1, value 2, " value 3," value 4, value 5 " ", value 6
I want to split this by comma and ignoring commas found in an expression enclosed by multiple double quotes
My desired output should be
value 1
value 2
" value 3," value 4, value 5 " "
value 6
I tried this Splitting on comma outside quotes but it doesn't work
Thanks in advance........Elsayed
Well first I would recommend to escape inner double quotes, e. g. value 1, value 2, " value 3,\" value 4, value 5 \" ", value 6. With this sort of syntax a method I use for this purpose is below. It is a little bit more complex than the first proposal, because it ignores blanks and line breaks between a comma and the next element in the list.
public static String[] splitSet(String inStr, char delimiter) {
if (inStr == null)
return null;
if (inStr.isEmpty())
return new String[]{};
/*
* add an empty element here and remove it at the end to simplify
* algorithm
*/
String delimiterStr = String.valueOf(delimiter);
String parseStr = inStr + delimiterStr + " ";
/*
* prepare parsing.
*/
Vector<String> list = new Vector<>();
String element = "";
int lc = 0;
char b = ' ';
char c;
boolean inBetweenQuotes = false;
/*
* parsing loop.
*/
while (lc < parseStr.length()) {
c = parseStr.charAt(lc);
/*
* add current entry and all following empty entries to list vector.
* Ignore space and new line characters following the delimiter.
*/
if ((c == delimiter) && !inBetweenQuotes) {
// flag to avoid adding empty elements for delimiter being blank
// or new line
boolean added = false;
while ((lc < parseStr.length())
&& ((c == delimiter) || (c == ' ') || (c == '\n'))) {
if ((c == delimiter)
&& !(added && ((c == ' ') || (c == '\n')))) {
list.add((String) UFormatter.parseElement(element,
DataType.STRING, delimiterStr));
element = "";
added = true;
}
lc++;
if (lc < parseStr.length())
c = parseStr.charAt(lc);
if (lc > 0)
b = parseStr.charAt(lc - 1);
}
}
/*
* add character to tmpList. Close String literal or Vector literal
*/
else {
element = element + c;
// toggle inBetweenQuotes at not escaped '"'
if ((c == '"') && (b != '\\'))
inBetweenQuotes = !inBetweenQuotes;
lc++;
b = c;
}
}
if (!element.isEmpty() && inBetweenQuotes)
list.add(element.substring(0, element.length() - 1) + "\"");
else if (!element.isEmpty())
list.add(element.substring(0, element.length() - 1));
// put Vector to array.
String[] ret = new String[list.size()];
for (int i = 0; i < list.size(); i++)
ret[i] = list.elementAt(i);
return ret;
}
I don't know how to use regex to solve it.
Is the double quotes included now? I haven't tried this code yet.
public static List<String> splitByComma(String text) {
ArrayList<String> ret = new ArrayList<>();
char[] chars = text.toCharArray();
boolean inQuote = false;
StringBuilder tmp = new StringBuilder();
for (char ch : chars) {
if (ch == ',') {
if (inQuote) tmp.append(ch);
else {
ret.add(tmp.toString());
tmp.setLength(0);
}
} else if (ch == '"') {
tmp.append(ch); // I just add this code
inQuote = !inQuote;
} else tmp.append(ch);
}
ret.add(tmp.toString());
return ret;
}
Please tell me if my code has any problem.
I've been having trouble with this assignment:
Given a string, replace the first occurrence of 'a' with "x", the second occurrence of 'a' with "xx" and the third occurrence of 'a' with "xxx". After the third occurrence, begin the replacement pattern over again with "x", "xx", "xxx"...etc.; however, if an 'a' is followed by more than 2 other 'a' characters in a row, then do not replace any more 'a' characters after that 'a'.
No use of the replace method is allowed.
aTo123X("ababba") → "xbxxbbxxx"
aTo123X("anaceeacdabnanbag") → "xnxxceexxxcdxbnxxnbxxxg"
aTo123X("aabaaaavfaajaaj") → "xxxbxxxaaavfaajaaj"
aTo123X("pakaaajaaaamnbaa") → "pxkxxxxxxjxxaaamnbaa"
aTo123X("aaaak") → "xaaak"
My code's output is with a's included, x's added but not the correct amount of x's.
public String aTo123X(String str) {
/*
Strategy:
get string length of the code, and create a for loop in order to find each individual part of the String chars.check for a values in string and take in pos of the a.
if one of the characters is a
replace with 1 x, however, there aren't more than 2 a's immediately following first a and as it keeps searching through the index, add more x's to the original string, but set x value back to 1 when x reaches 3.
if one of characters isn't a,
leave as is and continue string.
*/
String xVal = "";
String x = "x";
String output = "";
for (int i = 0; i < str.length(); i++){
if( str.charAt(i) == 'a'){
output += x;
str.substring(i+1, str.length());
}
output += str.charAt(i);
}
return output;
}
This is the code that does the same. I've commented the code to explain what it does
public class ReplaceChar {
public static void main(String... args){
String[] input =new String[]{"ababba","anaceeacdabnanbag","aabaaaavfaajaaj"};
StringBuilder result = new StringBuilder();
for (int i= 0; i < input.length;i++){
result.append(getReplacedA(input[i]));
result.append("\n");
}
System.out.println(result);
}
private static String getReplacedA(String withA){
// stringBuilder for result
StringBuilder replacedString = new StringBuilder();
// counting the number of time char 'a' occurred in String for replacement before row of 'aaa'
int charACount = 0;
// get the first index at which more than two 'aa' occurred in a row
int firstIndexOfAAA = withA.indexOf("aaa") + 1;
// if 'aaa' not occurred no need to add the rest substring
boolean addSubRequired = false;
// if the index is 0 continue till end
if (firstIndexOfAAA == 0)
firstIndexOfAAA = withA.length();
else
addSubRequired = true;
char[] charString = withA.toCharArray();
//Replace character String[] array
String[] replace = new String[]{"x","xx","xxx"};
for(int i = 0; i < firstIndexOfAAA; i++){
if (charString[i] == 'a'){
charACount++;
charACount = charACount > 3 ? 1 : charACount ;
// add the number x based on charCount
replacedString.append(replace[charACount - 1]);
}else{
replacedString.append(charString[i]);
}
}
// if the String 'aaa' has been found previously add the remaining subString
// after that index
if (addSubRequired)
replacedString.append(withA.substring(firstIndexOfAAA));
// return the result
return replacedString.toString();
}
}
Output:
xbxxbbxxx
xnxxceexxxcdxbnxxnbxxxg
xxxbxxxaaavfaajaaj
EDIT : Some Improvement You can make for some corner cases in the getReplacedA() function:
Check if char 'a' is there or not in the String if not just return the String No need to do anything further.
Use IgnoreCase to avoid the uppercase or lowercase possibility.
Firstly, string is immutable, so the below statement does nothing
str.substring(i+1, str.length());
I guess you wanted to do:
str = str.substring(i+1, str.length());
However, even after fix that, your program still doesn't work. I can't really comprehend your solution. 1) you are not detecting more than 3 a's in a row. 2) you are not appending "xx" or "xxx" at all
Here is my version, works for me so far:
public static void main(String[] args) {
System.out.println(aTo123X("ababba")); // "xbxxbbxxx"
System.out.println(aTo123X("anaceeacdabnanbag")); // "xnxxceexxxcdxbnxxnbxxxg"
System.out.println(aTo123X("aabaaaavfaajaaj")); // "xxxbxxxaaavfaajaaj"
}
public static String aTo123X(String str) {
String output = "";
int aOccurrence = 0;
String[] xs = {"x", "xx", "xxx"};
for (int i = 0; i < str.length(); ++i) {
if (str.charAt(i) == 'a') {
output += xs[aOccurrence % 3]; // append the x's depending on the number of a's we have seen, modulus 3 so that it forms a cycle of 3
if (i < str.length() - 3 && str.charAt(i + 1) == 'a' && str.charAt(i + 2) == 'a' && str.charAt(i + 3) == 'a') {//if an 'a' is followed by more than 2 other 'a' characters in a row
output += str.substring(i + 1);
break;
} else {
++aOccurrence; // increment the a's we have encountered so far
}
} else {
output += str.charAt(i); // append the character if it is not a
}
}
return output;
}
public class NewClass {
public static void main(String[] args) {
System.out.println(aTo123X("ababba")); // "xbxxbbxxx"
System.out.println(aTo123X("anaceeacdabnanbag")); // "xnxxceexxxcdxbnxxnbxxxg"
System.out.println(aTo123X("aabaaaavfaajaaj")); //xxxbxxxaaavfaajaaj
}
public static String aTo123X(String str) {
String output = "";
int aCount = 0;
int inRow = 0;
for (int i = 0; i < str.length();) {
if (str.charAt(i) == 'a') {
if (inRow <= 1) {
inRow++;
aCount++;
if (aCount == 1) {
output += "x";
} else if (aCount == 2) {
output += "xx";
} else {
output += "xxx";
aCount = 0;
}
boolean multiple = ((i + 1) < str.length()) && (str.charAt(i + 1) == 'a')
&& ((i + 2) < str.length()) && (str.charAt(i + 2) == 'a');
if (multiple) {
i++;
while (i < str.length()) {
output += str.charAt(i++);
}
return output;
}
} else {
output += str.charAt(i);
}
} else {
output += str.charAt(i);
inRow = 0;
}
i++;
}
return output;
}
}
I am pointing out problems in your code in form of comments in the code itself.
public String aTo123X(String str) {
//You are not using xVal variable in your code, hence it's obsolete
String xVal = "";
//You don't need x variable as you can simply use string concatenation
String x = "x";
String output = "";
for (int i = 0; i < str.length(); i++) {
/**
* Here, in "if" block you have not implmented any logic to replace the 2nd and
* 3rd occurence of 'a' with 'xx' and 'xxx' respectively. Also, substring() returns
* the sub-string of a string but you are not accepting that string anywhere, and
* you need not even use sub-string as "for" loop will cycle through all the
* characters in the string. If use sub-string method you code will only process
* alternative characters.
*/
if( str.charAt(i) == 'a') {
output += x;
str.substring(i+1, str.length());
}
/**
* Because of this statement a's are also returned, because this statement gets
* in both scenarios, whether the current character of string is a or not.
* But, this statement should get executed only when current character of the
* string is 'a'. So, in terms of coding this statement gets executed no matter
* "if" loop is executed or not, but it should get executed only when "if" loop
* is not executed. So, place this statement in else block.
*/
output += str.charAt(i);
}
return output;
}
I have implemented the logic for you. Here is Solution for your problem, just copy and run it. It passes all the specified test cases.
public String aTo123X(String str) {
String output = "";
int count = 1;
boolean flag = true;
for (int i = 0; i < str.length(); i++) {
if(str.charAt(i) == 'a' && flag == true) {
switch(count) {
case 1: output += "x";
count++;
break;
case 2: output += "xx";
count++;
break;
case 3: output += "xxx";
count = 1;
break;
}
if ((str.charAt(i+1) == 'a' && str.charAt(i+2) == 'a') == true) {
flag = false;
}
}
else {
output += str.charAt(i);
}
}
return output;
}
I use Map To store where to replace
public static void main(String[] args) {
System.out.println(aTo123X("ababba"));//xbxxbbxxx
System.out.println(aTo123X("anaceeacdabnanbag"));//xnxxceexxxcdxbnxxnbxxxg
System.out.println(aTo123X("aabaaaavfaajaaj"));//xxxbxxxaaavfaajaaj
}
public static String aTo123X(String str){
String res = "";
int nthReplace = 1; //Integer to store the nth occurence to replace
//Map to store [key == position of 'a' to replace]
//[value == x or xx or xxx]
Map<Integer, String> toReplacePos = new HashMap<>();
//The loop to know which 'a' to replace
for (int i = 0; i < str.length(); i++) {
if(str.charAt(i) == 'a'){
toReplacePos.put(i, nthReplace % 3 == 1 ? "x": (nthReplace % 3 == 2 ? "xx": "xxx"));
nthReplace++;
//Break if an 'a' is followed by more than 2 other 'a'
try {
if((str.charAt(i+1) == 'a')
&& (str.charAt(i+2) == 'a')
&& (str.charAt(i+3) == 'a')){
break;
}
} catch (StringIndexOutOfBoundsException e) {
}
}
}
//Do the replace
for (int i = 0; i < str.length(); i++) {
res += toReplacePos.containsKey(i) ? toReplacePos.get(i) : str.charAt(i);
}
return res;
}
I have edited my answer. This one is giving the correct solution:
public static void main (String[] args) throws InterruptedException, IOException, JSONException {
System.out.println(aTo123X("ababba")); //xbxxbbxxx
System.out.println(aTo123X("anaceeacdabnanbag")); //xnxxceexxxcdxbnxxnbxxxg
System.out.println(aTo123X("aabaaaavfaajaaj")); //xxxbxxxaaavfaajaaj
}
public static String aTo123X(String str) {
String x = "x";
String xx = "xx";
String xxx = "xxx";
int a = 1;
int brek = 0;
String output = "";
for (int i = 0; i < str.length(); i++) {
if(str.charAt(i) == 'a' && a == 1) {
output += x;
str.substring(i+1, str.length());
a = 2;
try {
if(str.charAt(i+1) == 'a' && str.charAt(i+2) == 'a')
brek += 1;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else if(str.charAt(i) == 'a' && a == 2) {
output += xx;
str.substring(i+1, str.length());
a = 3;
try {
if(str.charAt(i+1) == 'a' && str.charAt(i+2) == 'a')
brek += 1;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else if(str.charAt(i) == 'a' && a == 3) {
output += xxx;
str.substring(i+1, str.length());
a = 1;
try {
if(str.charAt(i+1) == 'a' && str.charAt(i+2) == 'a')
brek += 1;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else {
output += str.charAt(i);
brek = 0;
}
if(brek>0) {
output += str.substring(i+1);
break;
}
}
return output;
}
I have java program, which will receive plain text from server. The plain text may contain URLs. Is there any Class in Java library to convert plain text to HTML text? Or any other library? If there are not then what is the solution?
You should do some replacements on the text programmatically. Here are some clues:
All Newlines should be converted to "<br>\n" (The \n for better readability of the output).
All CRs should be dropped (who uses DOS encoding anyway).
All pairs of spaces should be replaced with " "
Replace "<" with "<"
Replace "&" with "&"
All other characters < 128 should be left as they are.
All other characters >= 128 should be written as "&#"+((int)myChar)+";", to make them readable in every encoding.
To autodetect your links, you could either use a regex like "http://[^ ]+", or "www.[^ ]" and convert them like JB Nizet said. to ""+url+"", but only after having done all the other replacements.
The code to do this looks something like this:
public static String escape(String s) {
StringBuilder builder = new StringBuilder();
boolean previousWasASpace = false;
for( char c : s.toCharArray() ) {
if( c == ' ' ) {
if( previousWasASpace ) {
builder.append(" ");
previousWasASpace = false;
continue;
}
previousWasASpace = true;
} else {
previousWasASpace = false;
}
switch(c) {
case '<': builder.append("<"); break;
case '>': builder.append(">"); break;
case '&': builder.append("&"); break;
case '"': builder.append("""); break;
case '\n': builder.append("<br>"); break;
// We need Tab support here, because we print StackTraces as HTML
case '\t': builder.append(" "); break;
default:
if( c < 128 ) {
builder.append(c);
} else {
builder.append("&#").append((int)c).append(";");
}
}
}
return builder.toString();
}
However, the link conversion has yet to be added. If someone does it, please update the code.
I found a solution using pattern matching. Here is my code -
String str = "(?i)\\b((?:https?://|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:\'\".,<>?«»“”‘’]))";
Pattern patt = Pattern.compile(str);
Matcher matcher = patt.matcher(plain);
plain = matcher.replaceAll("$1");
And Here are the input and output -
Input text is variable plain:
some text and then the URL http://www.google.com and then some other text.
Output :
some text and then the URL http://www.google.com and then some other text.
Just joined the coded from all answers:
private static String txtToHtml(String s) {
StringBuilder builder = new StringBuilder();
boolean previousWasASpace = false;
for (char c : s.toCharArray()) {
if (c == ' ') {
if (previousWasASpace) {
builder.append(" ");
previousWasASpace = false;
continue;
}
previousWasASpace = true;
} else {
previousWasASpace = false;
}
switch (c) {
case '<':
builder.append("<");
break;
case '>':
builder.append(">");
break;
case '&':
builder.append("&");
break;
case '"':
builder.append(""");
break;
case '\n':
builder.append("<br>");
break;
// We need Tab support here, because we print StackTraces as HTML
case '\t':
builder.append(" ");
break;
default:
builder.append(c);
}
}
String converted = builder.toString();
String str = "(?i)\\b((?:https?://|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:\'\".,<>?«»“”‘’]))";
Pattern patt = Pattern.compile(str);
Matcher matcher = patt.matcher(converted);
converted = matcher.replaceAll("$1");
return converted;
}
Use this
public static String stringToHTMLString(String string) {
StringBuffer sb = new StringBuffer(string.length());
// true if last char was blank
boolean lastWasBlankChar = false;
int len = string.length();
char c;
for (int i = 0; i < len; i++) {
c = string.charAt(i);
if (c == ' ') {
// blank gets extra work,
// this solves the problem you get if you replace all
// blanks with , if you do that you loss
// word breaking
if (lastWasBlankChar) {
lastWasBlankChar = false;
sb.append(" ");
} else {
lastWasBlankChar = true;
sb.append(' ');
}
} else {
lastWasBlankChar = false;
//
// HTML Special Chars
if (c == '"')
sb.append(""");
else if (c == '&')
sb.append("&");
else if (c == '<')
sb.append("<");
else if (c == '>')
sb.append(">");
else if (c == '\n')
// Handle Newline
sb.append("<br/>");
else {
int ci = 0xffff & c;
if (ci < 160)
// nothing special only 7 Bit
sb.append(c);
else {
// Not 7 Bit use the unicode system
sb.append("&#");
sb.append(new Integer(ci).toString());
sb.append(';');
}
}
}
}
return sb.toString();
}
If your plain text is a URL (which is different from containing a hyperlink, as you wrote in your question), then transforming it into a hyperlink in HTML is simply done by
String hyperlink = "<a href='" + url + "'>" + url + "</a>";
In Android application I just implemented HTMLifying of a content ( see https://github.com/andstatus/andstatus/issues/375 ). Actual transformation was done in literary 3 lines of code using Android system libraries. This gives an advantage of using better implementation at each subsequent version of Android libraries.
private static String htmlifyPlain(String textIn) {
SpannableString spannable = SpannableString.valueOf(textIn);
Linkify.addLinks(spannable, Linkify.WEB_URLS);
return Html.toHtml(spannable);
}
i want to test if current char current is not ',', '-', '.' or ' '
Is there a shorter expression for:
if((current != ' ') || (current != '.') || ...)
any ideas?
EDIT:
I am just allowed to use the methods nextChar and getChar. I have to loop through the chars.
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class WoerterZaehlen {
public static void main(String[] args) {
int wordCount = 0;
/* Ab hier dürft ihr eigenen Code einfügen */
char previous = ' ';
while(hasNextChar()){
char current = getChar();
if(current != )
//if(((current == ' ') || (current == '.') || (current == ',')) && ((previous != ' ') && (previous != ','))){
// wordCount++;
//}
previous = current;
}
/* Ab hier dürft ihr nichts mehr ändern. */
System.out.println("Anzahl der Wörter: " + wordCount);
}
private static InputStreamReader reader;
private static int next = -1;
public static boolean hasNextChar() {
if(next != -1)
return true;
try {
if(reader == null)
reader = new InputStreamReader(new FileInputStream("textdatei.txt"));
next = reader.read();
} catch (IOException e) {
System.out.println("Datei wurde nicht gefunden.");
}
return next != -1;
}
public static char getChar() {
char c = (char) next;
next = -1;
return c;
}
}
Try
String prohibitedChars = ",-. ";
boolean isProhibited = prohibitedChars.indexOf('-') > -1;
I cleaned it up to appear a bit nice, but if you're really after short then all you need is:
",-. ".indexOf('-') > -1;
EDIT:
You can still use this approach even if you are limited to getChar() and hasNextChar()
while(hasNextChar()){
char current = getChar();
if (",-. ".indexOf(current) > -1) {
wordCount++;
}
previous = current;
}
BitSet unwantedChars=new BitSet();
unwantedChars.set('.');
unwantedChars.set(',');
unwantedChars.set('-');
unwantedChars.set(' ');
char current=',';
if(unwantedChars.get(current)) //true if unwanted char else false
{
//....
}
Using Google Guava:
CharMatcher unwantedChars=CharMatcher.anyOf("-,. ").precomputed();
unwantedChars.apply(',');//true if unwanted char else false
if you are not allowed to use String.indexOf like in:
if (" .,".indexOf(ch) != -1) {
/* do something */
} else {
/* do if none of the above */
}
use a switch like in
switch (ch) {
case ' ': case '.': case ',': /* do something */ break;
default: /* do if none of the above */ break;
}
(instead of saving the previous char, you could just use a boolean to indicate if the previous char was a word boundary or a legal word character)
If it is an entire string you are looping through you might want to consider using regular expressions.
An example of validating with regex:
Checking String for illegal characters using regular expression
The example is white-listing character rather than blacklisting. This would in most cases be the preferred option as there is far more legal character-ranges than illegal.
or if you wanted to be ridiculous put the chars in a static BitSet, and use isSet(current).
Unless this code is going to be executed millions of times, i'd stick with what you have, as code clarity is more important than unmeasurable performance gains.
since many provide other solutions i'll provide the one you would use without the limitations.
String prohibitedChars = ",-. ";
prohibitedChars.contains(char);