JSP JSTL funciton fn:split is not working properly - java

Today, I come across one issue and need your help to fix it.
I am trying to split the string using JSTL fn:split function that is likewise,
<c:set var="stringArrayName" value="${fn:split(element, '~$')}" />
Actual String :- "abc~$pqr$xyz"
Expected Result :-
abc
pqr$xyz
only 2-string part expecting, but it gives
abc
pqr
xyz
here, total 3-string parts returning, which is wrong.
NOTE :- I have added <%#taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> at the top of JSP.
any help really appreciates!!

JSTL split not work like the Java split you can check the difference from the code source :
org.apache.taglibs.standard.functions.Functions.split
public static String[] split(String input, String delimiters) {
String[] array;
if (input == null) {
input = "";
}
if (input.length() == 0) {
array = new String[1];
array[0] = "";
return array;
}
if (delimiters == null) {
delimiters = "";
}
StringTokenizer tok = new StringTokenizer(input, delimiters);
int count = tok.countTokens();
array = new String[count];
int i = 0;
while (tok.hasMoreTokens()) {
array[i++] = tok.nextToken();
}
return array;
}
java.lang.String.split
public String[] split(String regex, int limit) {
return Pattern.compile(regex).split(this, limit);
}
So it's clearly that fn:split use StringTokenizer
...
StringTokenizer tok = new StringTokenizer(input, delimiters);
int count = tok.countTokens();
array = new String[count];
int i = 0;
while (tok.hasMoreTokens()) {
array[i++] = tok.nextToken();
}
...
Not like java.lang.String.split which use regular expression
return Pattern.compile(regex).split(this, limit);
//-----------------------^
from the StringTokenizer documentation it says :
Constructs a string tokenizer for the specified string. The characters
in the delim argument are the delimiters for separating tokens.
Delimiter characters themselves will not be treated as tokens.
How `fn:split` exactly work?
It split on each character in the delimiter, in your case you have two characters ~ and $ so if your string is abc~$pqr$xyz it will split it like this :
abc~$pqr$xyz
^^ ^
1st split :
abc
$pqr$xyz
2nd split :
abc
pqr$xyz
3rd split :
abc
pqr
xyz
Solution
use split in your Servlet instead of JSTL
for example :
String[] array = "abc~$pqr$xyz".split("~\\$");

Related

Spliting String into sections with keywords

I have a String i read from a .txt file with has values in sections seperated like
Text first
[section_name_1]
Text with values pattern1
...
[section_name_2]
Text with values pattern2
I need to split the sections at the section_name_# marks and add those to a String [] (Size of the array is fixed). My Code by now does not make some weird output:
//Code:
public static String[] parseFileToParams(File file)
{
String[] sections= {"[section_name_1]","[section_name_2]","[section_name_3]","[section_name_4]"};
String[] params = new String[sections.length+1];
StringBuilder sb = new StringBuilder();
String decoded = parseFile(file);// Returns the Text from the file
for(int i=0; i< sections.length;i++)
{
params[i]= decoded.split(sections[i])[1];
sb.append(params[i]);
}
return params;
}
//For Test of the output
String[] textArray = BasicOsuParser.parseFileToParams(parseFile);
for(int j = 0; j<textArray.length;j++)
{
sb.append(textArray[j]);
}
String text= sb.toString();
System.out.println (text); //Output: su f form formau fnull
// Obviously not how it should look like
Thanks for help!
Try this:
String[] sections= {"[section_name_1]","[section_name_2]","[section_name_3]","[section_name_4]"};
String textFromFile = "Text first [section_name_1] Text with values pattern1 [section_name_2] Text with values pattern2";
int count = 0;
for(int i = 0; i < sections.length; i++){
if(textFromFile.contains(sections[i])){//Use this to tell how big the parms array will be.
count++;
}
sections[i] = sections[i].replace("[", "\\[").replace("]", "\\]");//Removes the brackets from being delimiters.
}
String[] parms = new String[count+1];//Where the split items will go.
int next = 0;//The next index for the parms array.
for(String sec : sections){
String split[] = textFromFile.split(sec);//Split the file's text by the sec
if(split.length == 2){
parms[next] = split[0];//Adds split to the parms
next++;//Go to the next index for the parms.
textFromFile = split[1];//Remove text which has just been added to the parms.
}
}
parms[next] = textFromFile;//Add any text after the last split.
for(String out : parms){
System.out.println(out);//Output parms.
}
This will do what you have asked and it is commented so you can see how it works.
It's not a good idea use split() only for a one delimiter in text. This method tries to separate the text by given regexp pattern and usually used where there are more than one given delimiter in the text. Also you should screen special symbols in reqexp like '.','[' and so on. read about patterns in java. In your case better use substring() and indexOf():
public static String[] parseFileToParams(File file)
{
String[] sections= {"[section_name_1]","[section_name_2]","[section_name_3]","[section_name_4]"};
String[] params = new String[sections.length+1];
String decoded = parseFile(file);// Returns the Text from the file
int sectionStart = 0;
for (int i = 0; i < sections.length; i++) {
int sectionEnd = decoded.indexOf(sections[i], sectionStart);
params[i] = decoded.substring(sectionStart, sectionEnd);
sectionStart = sectionEnd + sections[i].length();
}
params[sections.length] = decoded.substring(sectionStart, decoded.length());
return params;
}
params[i]= decoded.split(sections[i])[1];
This returns the string after the first appearance of the sections[i] i.e. not just until the section[i+1] but till the end of file.
This loop,
for(int i=0; i< sections.length;i++)
{
params[i]= decoded.split(sections[i])[1];
sb.append(params[i]);
}
return params;
Repeatedly splits decoded into 2 halves, separated by the given section. You then append the entire 2nd half into params.
Example, pretend you wanted to split the string "abcdef" along "a", "b", etc.
You would split along a, and append "bcdef" to params, then split along b, and append "cdef" to params, etc., so you would get "bcdefcdef...f".
I think what you want to do is use real regex as the delimiter, something like params = decoded.split([section_name_.]). Look at http://www.tutorialspoint.com/java/java_string_split.htm and https://msdn.microsoft.com/en-us/library/az24scfc(v=vs.110).aspx
and if you want t

How do you rebuild a string using StringBuilder?

Im trying to rebuild a string using StringBuilder. I'm a little unsure of which method to use to get the "'," inserted back into the same place. In the code below I'm using the
"insert(int dstOffset, CharSequence s, int start, int end)" method. My code doesn't contain any errors however it doesn't run properly.
Please note I will also be escaping characters (i.e., =) in the string but I havent written that part of the code yet. Currently I'm trying to learn how to split the string and then rebuild it.
Thanks
public class StringTestProgram
{
public static void main(String[] args)
{
String relativeDN = "cn=abc,dn=xyz,ou=abc/def";
String[] stringData = relativeDN.split(",");
for (String stringoutput : stringData)
{
System.out.print(stringoutput);
StringBuilder sb = new StringBuilder(stringoutput);
CharSequence charAdded = ",";
sb.insert(6,charAdded,0,12);
System.out.print(sb.toString());
}
}
}
Revised code
public class StringTestProgram {
public static void main(String[] args) {
String relativeDN = "cn=abc,dn=xyz,ou=abc/def";
System.out.println(relativeDN);
//Split String
String[] stringData = relativeDN.split(",");
{
StringBuilder sb = new StringBuilder();
CharSequence charAdded = ",";
// loop thru each element of the array
for (int place = 0; place < stringData.length; place++) {
System.out.println(stringData[place]);
{
int eq = relativeDN.indexOf('=');
String sub = relativeDN.substring(0, eq);
System.out.println(sub);
}
// append element to the StringBuilder
sb.append(stringData[place]);
// avoids adding an extra ',' at the end
if (place < stringData.length - 1)
// if not at the last element, add the ',' character
sb.append(charAdded);
}
System.out.print(sb.toString());
}
}
}
Im new to stackoverflow and I'm not sure if its ok to ask this question in this thread or if I should create a seperate thread for this question. If possible please advise.
The code above now splits the string at the "," character. It also rebuilds the
string back to its original state. I would also like to use the indexof and .substring
methods to get the string value after the "=" sign. Currently my program only outputs
the first two characters of the initial string value before the "=" sign. Not sure where
in my code I'm making an error. Any help would be appreciated.
My Current Output
cn=abc,dn=xyz,ou=abc/def
cn=abc
cn
dn=xyz
cn
ou=abc/def
cn
cn=abc,dn=xyz,ou=abc/def
Desired Output
cn=abc,dn=xyz,ou=abc/def
cn=abc
abc
dn=xyz
xyz
ou=abc/def
abc/def
cn=abc,dn=xyz,ou=abc/def
The easiest way to do this pre Java 8 is to use 1 StringBuilder for all the elements and add Strings to the builder by using the append() method
StringBuilder builder = new StringBuilder();
for (String stringoutput : stringData) {
builder.append(stringoutput).append(',');
}
//have an extra trailing comma so remove it
//use length -1 as end coord because it's exclusive
String result = builder.substring(0, builder.length() -1);
If you are using Java 8 you can use the new Stream API and Collectors.joining()
String result = Arrays.stream(relativeDN.split(","))
.collect(Collectors.joining(","));
You're initializing sb every time you enter the loop, meaning that you're disposing of your StringBuilder every time you enter the loop and recreate it with only the next subtring.
Fixed:
String relativeDN = "cn=abc,dn=xyz,ou=abc/def";
String[] stringData = relativeDN.split(",");
StringBuilder sb = new StringBuilder();
CharSequence charAdded = ",";
for (String stringoutput : stringData) {
System.out.print(stringoutput);
sb.append(stringoutput).append(charAdded);
}
sb.setLength(sb.length() - 1);
System.out.print(sb.toString());
Try out this code
public class StringTestProgram {
public static void main(String[] args) {
String relativeDN = "cn=abc,dn=xyz,ou=abc/def";
String[] stringData = relativeDN.split(",");
StringBuilder sb = new StringBuilder();
CharSequence charAdded = ",";
for (int i = 0; i < stringData .length; i++) { //walk over each element of the array
System.out.println(stringData[i]);
sb.append(stringData[i]); // append element to the StringBuilder
if (i < stringData.length - 1) //avoids adding an extra ',' at the end
sb.append(charAdded); // if not at the last element, add the ',' character
}
System.out.print(sb.toString());
}
}
Here you will reconstruct the original string exactly as it was (i.e. without adding a trailing ','):
cn=abc,dn=xyz,ou=abc/def
UPDATE: In the for loop I just walk over every element of the array that stores the splitted String and append the elements to the StringBuilder instance one by one. After appending each element I check if we are currently at the last element of the array. If not, I append the ',' character.
Like this:
for (String stringoutput : stringData)
sb.append(stringoutput).append(',');
Fixed: Using this approach, you would have to remove the last ,
String result = sb.toString().substring(0,sb.toString().length()-1);
System.out.println(result);
I noticed in the other answers that there would be an extra comma at the end. You have to use a prefix variable and then change it in the loop so that there won't be an extra comma.
String relativeDN = "cn=abc,dn=xyz,ou=abc/def";
String[] stringData = relativeDN.split(",");
StringBuilder sb = new StringBuilder();
String prefix = "";
for (String element : stringData) {
sb.append(prefix);
prefix=",";
sb.append(element);
}
String output = sb.toString();
Inside the loop the prefix is appended, but on the first time through the loop the prefix is set to empty quotes so that there won't be a comma before the first element. Next prefix is changed to a comma so that in the next turn through the loop a comma will be added after the first element. Lastly, the element is added. This results in the correct output because the comma is added before the element, but only after the first iteration.

Checking whether the String contains multiple words

I am getting the names as String. How can I display in the following format: If it's single word, I need to display the first character alone. If it's two words, I need to display the first two characters of the word.
John : J
Peter: P
Mathew Rails : MR
Sergy Bein : SB
I cannot use an enum as I am not sure that the list would return the same values all the time. Though they said, it's never going to change.
String name = myString.split('');
topTitle = name[0].subString(0,1);
subTitle = name[1].subString(0,1);
String finalName = topTitle + finalName;
The above code fine, but its not working. I am not getting any exception either.
There are few mistakes in your attempted code.
String#split takes a String as regex.
Return value of String#split is an array of String.
so it should be:
String[] name = myString.split(" ");
or
String[] name = myString.split("\\s+);
You also need to check for # of elements in array first like this to avoid exception:
String topTitle, subTitle;
if (name.length == 2) {
topTitle = name[0].subString(0,1);
subTitle = name[1].subString(0,1);
}
else
topTitle = name.subString(0,1);
The String.split method split a string into an array of strings, based on your regular expression.
This should work:
String[] names = myString.split("\\s+");
String topTitle = names[0].subString(0,1);
String subTitle = names[1].subString(0,1);
String finalName = topTitle + finalName;
First: "name" should be an array.
String[] names = myString.split(" ");
Second: You should use an if function and the length variable to determine the length of a variable.
String initial = "";
if(names.length > 1){
initial = names[0].subString(0,1) + names[1].subString(0,1);
}else{
initial = names[0].subString(0,1);
}
Alternatively you could use a for loop
String initial = "";
for(int i = 0; i < names.length; i++){
initial += names[i].subString(0,1);
}
You were close..
String[] name = myString.split(" ");
String finalName = name[0].charAt(0)+""+(name.length==1?"":name[1].charAt(0));
(name.length==1?"":name[1].charAt(0)) is a ternary operator which would return empty string if length of name array is 1 else it would return 1st character
This will work for you
public static void getString(String str) throws IOException {
String[] strr=str.split(" ");
StringBuilder sb=new StringBuilder();
for(int i=0;i<strr.length;i++){
sb.append(strr[i].charAt(0));
}
System.out.println(sb);
}

Equivalent to StringTokenizer with multiple characters delimiters

I try to split a String into tokens.
The token delimiters are not single characters, some delimiters are included into others (example, & and &&), and I need to have the delimiters returned as token.
StringTokenizer is not able to deal with multiple characters delimiters. I presume it's possible with String.split, but fail to guess the magical regular expression that will suits my needs.
Any idea ?
Example:
Token delimiters: "&", "&&", "=", "=>", " "
String to tokenize: a & b&&c=>d
Expected result: an string array containing "a", " ", "&", " ", "b", "&&", "c", "=>", "d"
--- Edit ---
Thanks to all for your help, Dasblinkenlight gives me the solution. Here is the "ready to use" code I wrote with his help:
private static String[] wonderfulTokenizer(String string, String[] delimiters) {
// First, create a regular expression that matches the union of the delimiters
// Be aware that, in case of delimiters containing others (example && and &),
// the longer may be before the shorter (&& should be before &) or the regexpr
// parser will recognize && as two &.
Arrays.sort(delimiters, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return -o1.compareTo(o2);
}
});
// Build a string that will contain the regular expression
StringBuilder regexpr = new StringBuilder();
regexpr.append('(');
for (String delim : delimiters) { // For each delimiter
if (regexpr.length() != 1) regexpr.append('|'); // Add union separator if needed
for (int i = 0; i < delim.length(); i++) {
// Add an escape character if the character is a regexp reserved char
regexpr.append('\\');
regexpr.append(delim.charAt(i));
}
}
regexpr.append(')'); // Close the union
Pattern p = Pattern.compile(regexpr.toString());
// Now, search for the tokens
List<String> res = new ArrayList<String>();
Matcher m = p.matcher(string);
int pos = 0;
while (m.find()) { // While there's a delimiter in the string
if (pos != m.start()) {
// If there's something between the current and the previous delimiter
// Add it to the tokens list
res.add(string.substring(pos, m.start()));
}
res.add(m.group()); // add the delimiter
pos = m.end(); // Remember end of delimiter
}
if (pos != string.length()) {
// If it remains some characters in the string after last delimiter
// Add this to the token list
res.add(string.substring(pos));
}
// Return the result
return res.toArray(new String[res.size()]);
}
It could be optimize if you have many strings to tokenize by creating the Pattern only one time.
You can use the Pattern and a simple loop to achieve the results that you are looking for:
List<String> res = new ArrayList<String>();
Pattern p = Pattern.compile("([&]{1,2}|=>?| +)");
String s = "s=a&=>b";
Matcher m = p.matcher(s);
int pos = 0;
while (m.find()) {
if (pos != m.start()) {
res.add(s.substring(pos, m.start()));
}
res.add(m.group());
pos = m.end();
}
if (pos != s.length()) {
res.add(s.substring(pos));
}
for (String t : res) {
System.out.println("'"+t+"'");
}
This produces the result below:
's'
'='
'a'
'&'
'=>'
'b'
Split won't do it for you as it removed the delimeter. You probably need to tokenize the string on your own (i.e. a for-loop) or use a framework like
http://www.antlr.org/
Try this:
String test = "a & b&&c=>d=A";
String regEx = "(&[&]?|=[>]?)";
String[] res = test.split(regEx);
for(String s : res){
System.out.println("Token: "+s);
}
I added the '=A' at the end to show that that is also parsed.
As mentioned in another answer, if you need the atypical behaviour of keeping the delimiters in the result, you will probably need to create you parser yourself....but in that case you really have to think about what a "delimiter" is in your code.

string tokenizer in Java

I have a text file which contains data seperated by '|'. I need to get each field(seperated by '|') and process it. The text file can be shown as below :
ABC|DEF||FGHT
I am using string tokenizer(JDK 1.4) for getting each field value. Now the problem is, I should get an empty string after DEF.However, I am not getting the empty space between DEF & FGHT.
My result should be - ABC,DEF,"",FGHT but I am getting ABC,DEF,FGHT
From StringTokenizer documentation :
StringTokenizer is a legacy class that
is retained for compatibility reasons
although its use is discouraged in new
code. It is recommended that anyone
seeking this functionality use the
split method of String or the
java.util.regex package instead.
The following code should work :
String s = "ABC|DEF||FGHT";
String[] r = s.split("\\|");
Use the returnDelims flag and check two subsequent occurrences of the delimiter:
String str = "ABC|DEF||FGHT";
String delim = "|";
StringTokenizer tok = new StringTokenizer(str, delim, true);
boolean expectDelim = false;
while (tok.hasMoreTokens()) {
String token = tok.nextToken();
if (delim.equals(token)) {
if (expectDelim) {
expectDelim = false;
continue;
} else {
// unexpected delim means empty token
token = null;
}
}
System.out.println(token);
expectDelim = true;
}
this prints
ABC
DEF
null
FGHT
The API isn't pretty and therefore considered legacy (i.e. "almost obsolete"). Use it only with where pattern matching is too expensive (which should only be the case for extremely long strings) or where an API expects an Enumeration.
In case you switch to String.split(String), make sure to quote the delimiter. Either manually ("\\|") or automatically using string.split(Pattern.quote(delim));
StringTokenizer ignores empty elements. Consider using String.split, which is also available in 1.4.
From the javadocs:
StringTokenizer is a legacy class that
is retained for compatibility reasons
although its use is discouraged in new
code. It is recommended that anyone
seeking this functionality use the
split method of String or the
java.util.regex package instead.
you can use the constructor that takes an extra 'returnDelims' boolean, and pass true to it.
this way you will receive the delimiters, which will allow you to detect this condition.
alternatively you can just implement your own string tokenizer that does what you need, it's not that hard.
Here is another way to solve this problem
String str = "ABC|DEF||FGHT";
StringTokenizer s = new StringTokenizer(str,"|",true);
String currentToken="",previousToken="";
while(s.hasMoreTokens())
{
//Get the current token from the tokenize strings
currentToken = s.nextToken();
//Check for the empty token in between ||
if(currentToken.equals("|") && previousToken.equals("|"))
{
//We denote the empty token so we print null on the screen
System.out.println("null");
}
else
{
//We only print the tokens except delimiters
if(!currentToken.equals("|"))
System.out.println(currentToken);
}
previousToken = currentToken;
}
Here is a way to split a string into tokens (a token is one or more letters)
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String s = scan.nextLine();
s = s.replaceAll("[^A-Za-z]", " ");
StringTokenizer arr = new StringTokenizer(s, " ");
int n = arr.countTokens();
System.out.println(n);
while(arr.hasMoreTokens()){
System.out.println(arr.nextToken());
}
scan.close();
}
package com.java.String;
import java.util.StringTokenizer;
public class StringWordReverse {
public static void main(String[] kam) {
String s;
String sReversed = "";
System.out.println("Enter a string to reverse");
s = "THIS IS ASHIK SKLAB";
StringTokenizer st = new StringTokenizer(s);
while (st.hasMoreTokens()) {
sReversed = st.nextToken() + " " + sReversed;
}
System.out.println("Original string is : " + s);
System.out.println("Reversed string is : " + sReversed);
}
}
Output:
Enter a string to reverse
Original string is : THIS IS ASHIK SKLAB
Reversed string is : SKLAB ASHIK IS THIS

Categories

Resources