StringIndexOutOfBoundsException: String index out of range: -3 - java

When I'm compiling and running my tests,
this message appears:
StringIndexOutOfBoundsException: String index out of range: -3
I think I've done something wrong with the substrings, but I can't figure out where.
This should be tested:
Argument for parsePathname: .mp3
Output getAuthor: empty String
Output getTitle: empty String
This is my code:
public void parseFilename(String filename)
{
//Dateiendung entfernen
int ending;
ending = filename.lastIndexOf('.');
filename = filename.substring(0,ending);
filetype = filename.substring(filename.length()-3);
//Abfrage, ob Bindestrich(hyphen) vorhanden
//i+1 ist Position vom Bindestrich
boolean has_hyphen = false;
int i;
for(i=0; i<filename.length(); i++)
{
if(filename.charAt(i) == ' ' && filename.charAt(i+1) == '-' && filename.charAt(i+2) == ' ')
{
has_hyphen = true;
break;
}
}
if (!has_hyphen || (filename.length() == 1 && filename.charAt(0) == '-'))
{
author ="";
title = filename;
}
if (filename.length() == 0 || (filename.charAt(0) == ' ' && filename.charAt(1) == '-' && filename.charAt(2) == ' '))
{
author = "";
title = "";
}
if (has_hyphen)
{
author = filename.substring(0,i);
author = author.trim();
title = filename.substring(i+2);
title = title.trim();
}
}

My guess would be that your exception occurs here:
ending = filename.lastIndexOf('.');
filename = filename.substring(0,ending);
filetype = filename.substring(filename.length()-3); //<- Here
If . is the first char of the filename (eg. ".mp3"), the index will be 0 and the substring afterwards will be a string of size 0.
Then you call substring with -3 and it throws a IndexOutOfBoundsException. Make sure the string contain more than just the file type.
If you know that the input parameter always will contain a file extension you could prevent it like this:
ending = filename.lastIndexOf('.');
if(ending == 0) {
filetype = filename;
filename = "";
} else {
...
You should get the filetype before you remove it to get the filename. After this line:
filename = filename.substring(0,ending);
filename no longer contains the file extension.

Related

How do I handle punctuation in this Pig Latin translator?

The rest of the code is working perfectly but I cannot figure out how to prevent punctuation from being translated.
public class PigLatintranslator
{
public static String translateWord (String word)
{
String lowerCaseWord = word.toLowerCase ();
int pos = -1;
char ch;
for (int i = 0 ; i < lowerCaseWord.length () ; i++)
{
ch = lowerCaseWord.charAt (i);
if (isVowel (ch))
{
pos = i;
break;
}
}
if (pos == 0 && lowerCaseWord.length () != 1) //translates if word starts with vowel
{
return lowerCaseWord + "way"; // Adding "way" to the end of string
}
else if (lowerCaseWord.length () == 1) //Ignores words that are only 1 character
{
return lowerCaseWord;
}
else if (lowerCaseWord.charAt(0) == 'q' && lowerCaseWord.charAt(1) == 'u')//words that start with qu
{
String a = lowerCaseWord.substring (2);
return a + "qu" + "ay";
}
else
{
String a = lowerCaseWord.substring (1);
String b = lowerCaseWord.substring (0,1);
return a + b + "ay"; // Adding "ay" at the end of the extracted words after joining them.
}
}
public static boolean isVowel (char ch) checks for vowel
{
if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u' || ch == 'y')
{
return true;
}
return false;
}
}
I need the translation to ignore punctuation. For example "Question?" should be translated to "estionquay?" (question mark still in the same position and not translated)
As Andreas said, if the function is expecting only one word, it should be the responsibility of the calling function to ensure there's no full sentence or punctuation being passed to it. With that said, if you require the translator to handle this, you need to find the index of the string where the punctuation or non-letter character occurs. I added in a main method to test the function:
public static void main(String[] args) {
System.out.println(translateWord("QUESTION?"));
}
I added a loop into the qu case to find the punctuation being input, the two checks are to see if the character at position i is inside the range of a - z. The sub-string then only goes to the point where the punctuation is found.
int i;
for (i = 0; i < lowerCaseWord.length(); i++) {
if(lowerCaseWord.charAt(i) > 'z' || lowerCaseWord.charAt(i) < 'a') {
break;
}
}
String a = lowerCaseWord.substring (2, i);
String b = lowerCaseWord.substring(i);
return a + "qu" + "ay" + b;
This may need some tweaking if you're worried about words with hyphens and whatnot but this should put across the basic idea.
Here's the output I received:
$javac PigLatintranslator.java
$java -Xmx128M -Xms16M PigLatintranslator
estionquay?

iText7.1.3 adding SVG into PdfDocument

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);
}

Splitting String by comma and ignore comma in multiple double quotes

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.

Converting infix to prefix using a Stack (LinkedList)

I am trying to write a method that converts infix to prefix and to do that i want to read a sting reverse and use a stack. When i execute this code i am getting an exception at character = expression.charAt(limit); how can i fix that code?
My input was 1+3 and the error i got was:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException:
String index out of range: 3 at java.lang.String.charAt(Unknown
Source) at PrefixTranslator.translate(PrefixTranslator.java:27) at
PrefixTranslatorTest.main(PrefixTranslatorTest.java:11)
PrefixTranslator Class:
public class PrefixTranslator
{
static private String expression;
private MyStack<Character> stack = new MyStack<Character>();
//Constructor
public PrefixTranslator(String infixExpression)
{
expression = infixExpression;
}//End of constructor
public String translate()
{
//Declare Method Variables
String input = "";
String output = "";
char character = ' ';
char nextCharacter = ' ';
for(int limit = expression.length(); limit > 0 ; limit--)
{
character = expression.charAt(limit);
if(isOperator(character))
{
output = output + character + " ";
}
else if(character == '(')
{
stack.push(character);
}
else if(character == ')')
{
while(!stack.top().equals('('))
output = output + stack.pop() + " ";
stack.pop();
}
else
{
if(Character.isDigit(character) && (limit + 1) < limit && Character.isDigit(expression.charAt(limit+1)))
{
stack.push(character);
stack.push(expression.charAt(limit+1));
}
else if(Character.isDigit(character))
{
stack.push(character);
}
else
{
output = output + character;
}
}
}//End of for
while(!stack.isEmpty())
{
output = output + stack.pop() + " ";
}
return output;
}//End of translate method
//Check priority on characters
public static int precedence(char operator)
{
if(operator == '+' || operator =='-')
return 1;
else if(operator == '*' || operator == '/')
return 2;
else
return 0;
}//End of priority method
public boolean isOperator(char element)
{
if(element == '*' || element == '-' || element == '/' || element == '+')
return true;
else
return false;
}//End of isOperator method
}//End of class
PrefixTranslatorTest Class:
import java.util.Scanner;
public class PrefixTranslatorTest{
public static void main(String[] args)
{
Scanner input = new Scanner(System.in);
System.out.println("Enter the expression that you want to convert to prefix.");
String expression = input.next();
PrefixTranslator translator = new PrefixTranslator(expression);
System.out.println(translator.translate());
}
}
For the given input 1+3 expression.length() returns 3 and you can refer to indexes 0-2 of that string. So, your loop shouldn't be:
for(int limit = expression.length(); limit > 0 ; limit--)
And it should be
for(int limit = expression.length() - 1; limit >= 0 ; limit--)
The first index of Java arrays is 0 and the method length() returns the number of elements of array. If you need the last element's index, use
length() - 1.
So instead of
for (int limit = expression.length(); limit > 0; limit--)
use
for (int limit = expression.length() - 1; limit >= 0; limit--)

How to use PropertyResourceBundle with keys containing whitespaces

I want to use properties files through PropertyResourceBundle for i18n. My current issue is that keys on the files I have can include white spaces, e.g. :
key number 1 = value number 1
key2 = value2
So, when I load the corresponding property file the first white space is used as the key-value delimiter instead of the '=' sign.
Then, my questions are: how can I use a key with white spaces in it without modifying the properties file (I'd like to avoid adding any slash or unicode character code)? Is there any way to override the default properties file delimiter so I can set '=' as the only one to be considered?
you will have to write your own Properties class, the one in the jdk considers white space as a separator, here is it's code. you'll find out that as soon as it encounter a white space it stop the key & start the value.
private void load0 (LineReader lr) throws IOException {
char[] convtBuf = new char[1024];
int limit;
int keyLen;
int valueStart;
char c;
boolean hasSep;
boolean precedingBackslash;
while ((limit = lr.readLine()) >= 0) {
c = 0;
keyLen = 0;
valueStart = limit;
hasSep = false;
//System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
precedingBackslash = false;
while (keyLen < limit) {
c = lr.lineBuf[keyLen];
//need check if escaped.
if ((c == '=' || c == ':') && !precedingBackslash) {
valueStart = keyLen + 1;
hasSep = true;
break;
} else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) {
valueStart = keyLen + 1;
break;
}
if (c == '\\') {
precedingBackslash = !precedingBackslash;
} else {
precedingBackslash = false;
}
keyLen++;
}
while (valueStart < limit) {
c = lr.lineBuf[valueStart];
if (c != ' ' && c != '\t' && c != '\f') {
if (!hasSep && (c == '=' || c == ':')) {
hasSep = true;
} else {
break;
}
}
valueStart++;
}
String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
put(key, value);
}
}

Categories

Resources