StringIndexOutOfBoundsException, delete whitespaces from a string method - java

I'm making a cryptography/cryptanalysis program using java as a homework for my master. Anyway, i use a method to delete the uselless whitespaces and make the String i display to the JTextArea proper. This method is great for small texts but it gives me a StringIndexOutOfBoundsException when i use bigger texts (loaded from a .txt file). Can anyone help?
Thanks in advance.
This is the method:
public void Data(String s) {
System.out.print("Analysis" + "\n" + s);
jTextArea1.setText(s);
StringBuilder buf = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if (!Character.isWhitespace(s.charAt(i))) {
buf.append(s.charAt(i));
} else if (Character.isWhitespace(s.charAt(i)) && !Character.isWhitespace(s.charAt(i + 1))) {
buf.append(s.charAt(i));
}
}
System.out.println(buf.toString() + "\n" + "from buf");
jTextArea1.setText(buf.toString());
}

You are going up to s.length() in the for loop but accessing s.charAt(i + 1) in the second if statement. Try to only go up to s.length() - 1:
for (int i = 0; i < s.length() - 1; i++) {
if (!Character.isWhitespace(s.charAt(i))) {
buf.append(s.charAt(i));
} else if (Character.isWhitespace(s.charAt(i)) && !Character.isWhitespace(s.charAt(i + 1))) {
buf.append(s.charAt(i));
}
}
And then check the last character afterwards.

s.charAt(i + 1) in !Character.isWhitespace(s.charAt(i + 1))
It fails when i == s.length() - 1
You might want to use s.replaceAll("\\s\\s+"," ") instead of reinventing the wheel.

You are using this statement
Character.isWhitespace(s.charAt(i + 1)
meaning you are accessing an character of your string length plus 1.

hi i hope you can use the below one, instead the above
//StringBuilder buf = new StringBuilder();
/* These lines are not needed
for (int i = 0; i < s.length(); i++) {
if (!Character.isWhitespace(s.charAt(i))) {
buf.append(s.charAt(i));
} else if (Character.isWhitespace(s.charAt(i)) && !Character.isWhitespace(s.charAt(i + 1))) {
buf.append(s.charAt(i));
}`enter code here`
}
*/
s = s.replaceAll("\\s+"," ");
// Whenever you print the object(reference) toString() method is called by default. so no need to call explicitly
// System.out.println(buf.toString() + "\n" + "from s");
System.out.println(s + "\n" + "from buf");
// jTextArea1.setText(s);
jTextArea1.setText(s);

Related

Implementing substring checking method using only charAt

I am trying to implement a substring method using only charAt method of the String class
The problem occurs when I include the last character in the search term 'hat.' otherwise everything works perfectly.
Also when searching for example for 'hat' I see the charAt(j) trace prints all 'h' with index 0 for all characters and true occurrence.
Here is the complete code:
public class SubString {
public static void main(String[] args) {
String line = "The cat in the hat.";
String item = "hat.";
System.out.println("'" + item + "' is substring of '" + line + "' : " + isSubString(item, line));
}
private static boolean isSubString(String item, String line) {
int i = 0;
int j = 0;
int count = 0;
for (i = 0; i < line.length() - item.length(); i++) {
for (j = 0; j < item.length(); j++) {
if (item.charAt(j) != line.charAt(i + j)) {
break;
}
if (item.charAt(j) == line.charAt(i + j)) {
System.out.println(item.charAt(j) + ":" + j + " - " + line.charAt(i + j) + ":" + (i + j));
count++;
}
if (count == item.length())
return true;
}
}
return false;
}
}
Again the problem occurs when searching for 'hat.' < == the last word with dot.
and the 'hat' which although return true but trace shows wrong characters ( only h's compared) and indexes are always 0.
The first loop omits the last character of the string. i.e, line.length() - item.length()
Please replace it with below for loop condition.
for (i = 0; i < line.length() - item.length() + 1; i++) {
you should try
line.contains(item)

String variable in nested for loop not getting modified

Before I get into the issue, let me describe the problem that the code is supposed to be solving.
The code is supposed to take in input from a file in the following syntax:
1,2,3,4;5
The code is supposed to take the integer that is after the semicolon and assign it to a variable, which it does. Then the code is supposed to take the values that are before the semicolon and find and return all two pairs of integers that add up to the value after the semicolon.
Example: if the input is
1,2,3,4;5
then the output should be
1,4;3,2
The problem I have is that my String result is not being edited by the nested for loops within the code. I get no compile time or runtime errors. It just does not edit the String result and I can't figure out why. Could you guys take a look?
import java.util.*;
import java.io.*;
public class NumberPairs2 {
public static void main (String[] args) throws IOException {
File file = new File("C:/Users/James/Desktop/txt.txt"); // Takes in a file as input
BufferedReader buffer = new BufferedReader(new FileReader(file));
String line;
while ((line = buffer.readLine()) != null) {
String result = ""; // creates an empty string
line = line.trim(); // set the file contents equal to null
if (line.length() != 0){
int sumTest = Integer.parseInt(line.substring(line.indexOf(";") + 1));
String[] intArray = line.split(";");
String[] intArray2 = intArray[0].split(",");
for (int i = 0; i < intArray2.length - 1; i++){
for(int j = i + 1; i < intArray2.length; i++){
if (intArray2[i] != "," && intArray2[j] != "," && Integer.parseInt(intArray2[i]) + Integer.parseInt(intArray2[j]) == sumTest){
result += intArray[i] + ", " + intArray[j] + ";";
System.out.println(result);
}
}
}
//int compare = ()
}
else {
result = null;
System.out.println(result);
}
}
}
}
This may help
for (int i = 0; i < intArray2.length - 1; i++){
for(int j = i + 1; j < intArray2.length; j++){
if (Integer.parseInt(intArray2[i]) + Integer.parseInt(intArray2[j]) == sumTest){
result += intArray2[i] + ", " + intArray2[j] + ";";
}
}
}
System.out.println(result);
You need to use intArray2[i] & intArray2[j] when adding to result instead of intArray[i] & intArray[j]. Your code is currently getting an ArrayIndexOutOfBoundsException while trying to use intArray2 indices in intArray.
for (int i = 0; i < intArray2.length - 1; i++){
for(int j = i + 1; j < intArray2.length; j++){
if (Integer.parseInt(intArray2[i]) + Integer.parseInt(intArray2[j]) == sumTest){
result += intArray2[i] + ", " + intArray2[j] + ";";
System.out.println(result);
}
}
}
one option to remove the last semicolon would be to append to result as follows
//if not 1st pair, add semicolon
if(!result.equals("")){
result += "; ";
}
result += intArray2[i] + ", " + intArray2[j];

Java Method is broken

I am trying to get it to return a compressed word. For example, reaction should be #act$. But it is getting returned as react$. I feel like my issue is not including the original word in the return statement. Can anyone help? Thanks!
public static String compress (String word) {
String newWord = "";
int the = word.indexOf("the");
if (the >= 0) {
newWord = word.substring(0,the) + "&" + word.substring(the+3);
}
int ion = newWord.indexOf("ion");
if (ion >= 0) {
newWord = newWord.substring(0,ion) + "$" + word.substring(ion+3);
}
int ing = newWord.indexOf("ing");
if (ing >= 0) {
newWord = newWord.substring(0,ing) + "~" + word.substring(ing+3);
}
int an = newWord.indexOf("an");
if (an >= 0) {
newWord = newWord.substring(0,an) + "#" + word.substring(an+2);
}
int re = newWord.indexOf("re");
if (re >= 0) {
newWord = newWord.substring(0,re) + "#" + word.substring(re+2);
}
int con = newWord.indexOf("con");
if (con >= 0) {
newWord = newWord.substring(0,con) + "%" + word.substring(con+3);
}
return newWord;
}
A compressed version also:
public static String compress(String word) {
word = word.replace("the", "&");
word = word.replace("ion", "$");
word = word.replace("ing", "~");
word = word.replace("an", "#");
word = word.replace("re","#");
word = word.replace("con","%");
return word;
}
You're mixing up your uses of newWord and word in a confusing way. If the first if clause doesn't fire, newWord will still be an empty string and none of the other conditions will fire. On the other hand, if newWord does get set to something, you still go on using word substrings, in ways that don't make any sense.
You would be better off just using one variable through the whole method.
public static String compress(String word) {
int the = word.indexOf("the");
if (the >= 0) {
word = word.substring(0,the) + "&" + word.substring(the+3);
}
int ion = word.indexOf("ion");
if (ion >= 0) {
word = word.substring(0,ion) + "$" + word.substring(ion+3);
}
int ing = word.indexOf("ing");
if (ing >= 0) {
word = word.substring(0,ing) + "~" + word.substring(ing+3);
}
int an = word.indexOf("an");
if (an >= 0) {
word = word.substring(0,an) + "#" + word.substring(an+2);
}
int re = word.indexOf("re");
if (re >= 0) {
word = word.substring(0,re) + "#" + word.substring(re+2);
}
int con = word.indexOf("con");
if (con >= 0) {
word = word.substring(0,con) + "%" + word.substring(con+3);
}
return word;
}
Note also that, written this way, you can only use each replacement once per word: if you have "thethe" you will compress it to "&the", not "&&". If you want use replacements multiple times, you would have to use a loop. Or, easier still, use String.replace.

if / else "last resort" while in a loop

here is the scoop. I have a program that loops through an ArrayList and checks to see if the values are equal to an inputted keyword(inputArray[0])
I want to add a default action incase inputArray[0] is not equal to any of the values inside of the keyList
The else if is where I am having the problem. I want my loop to go through ALL of the values in keyList before it resorts the "last resort" - an else statement. Right now my problem is that in the first if statement it sees that inputArray[0] is not equal to keyList[x] and it goes to the else statement without going through another run of the loop.
As you can see, I tried using an else if statement, where if my loop's counter, x, is larger than the size of keyList then it will do the code inside, but that seemingly does not work. I also added continue;to the else statement to ensure that it is going through the loop, which according to the console, it is. (I know because of the System.out statement at the beginning of the loop.)
public static void wikiInit(ArrayList keyList, ArrayList nameList, ArrayList domainList, ArrayList softwareList, String[] inputArray, EntityPlayer player)
{
System.out.println("These are the current lists:");
System.out.println("Key List: " + keyList);
System.out.println("Name List: " + nameList);
System.out.println("Domain List: " + domainList);
System.out.println("Software List: " + softwareList);
// KEY PARSER
for(int x = 0; x < keyList.size(); x++)
{
System.out.println("Starting the loop");
if((keyList.get(x)).equals(inputArray[0]))
{
//getWikiName = wikiNameArray[x]
//getWikiDomain = wikiDomainArray[x]
//getWikiSoftware = wikiSoftwareArray[x]
StringBuilder hyperlinkBuilder = new StringBuilder();
for(int y = 1; y < inputArray.length; y++)
{
hyperlinkBuilder.append(inputArray[y] + " ");
}
if((softwareList.get(x)).equals("MEDIAWIKI"))
{
String hyperlink = "http://" + domainList.get(x) + "/index.php?search=" + hyperlinkBuilder.toString();
System.out.println("Searching for " + hyperlinkBuilder.toString() + " on the " + nameList.get(x));
player.addChatMessage("Searching for " + hyperlinkBuilder.toString() + " on the " + nameList.get(x));
BrowserHandler.browserInit(hyperlink.replace(" ", "+"), player);
System.out.println("Opening " + hyperlink.replace(" ", "+"));
break;
}
}
else if(x > keyList.size())
{//LAST RESORT
}
else
{
continue;
}
}
}
instead of loop use
if(keyList.contains(inputArray[0])){
int x = keyList.indexOf(inputArray[0]);
StringBuilder hyperlinkBuilder = new StringBuilder();
for(int y = 1; y < inputArray.length; y++)
...
}
else { // last resort code
}
If the default action should only happen after all elements have been checked, it should happen outside the loop. You can do this by using a variable to signal when this happens:
boolean found = false;
for(int x = 0; x < keyList.size(); x++)
{
System.out.println("Starting the loop");
if((keyList.get(x)).equals(inputArray[0]))
{
found = true;
...
}
}
if (!found) {
//The value was never found, do something special.
}
Having said that, in this case it would be much easier to use keyList.contains, as in bellabax's answer.
One way is to simply set a found variable to false before the loop and set it to true inside the loop if you find a key match.
Then after the loop:
if (!found)
complainBitterly();
Try using a boolean. Set it to false before the for loop, and if inputArray[0] is equal to keyList[x], set the boolean to true (in your if statement).
Then have an if statement after the for loop that will do your last case resort if the bool is still false.
The good news is you can make this a lot simpler by making 2 changes.
First, extract those 4 separate lists that you reference and combine them as a list of objects with fields for each list, 'ParameterTuplein the code. Second, you can track loop exit status with another variable,foundMediaWikiKey` in the code.
/**
* Not sure of a better name for this class, you'll need to look at in the larger sense.
* Also, in production you probably want to use getters for these, rather than final
* public and the constructor
*/
public class ParameterTuple {
public ParameterTuple(String key, String name, String domain, String software) {
this.key = key;
this.name = name;
this.domain = domain;
this.software = software;
}
public final String key;
public final String name;
public final String domain;
public final String software;
}
public static void wikiInit(ArrayList<ParameterTuple> paramList, String[] inputArray, EntityPlayer player) {
System.out.println("These are the current lists:");
System.out.println("List: " + paramList);
// Variable to keep track of how we exited the loop.
boolean foundMediaWikiKey = false;
// KEY PARSER
for(ParameterTuple param : paramList)
{
System.out.println("Starting the loop");
if(param.key.equals(inputArray[0])) {
StringBuilder hyperlinkBuilder = new StringBuilder();
for(int y = 1; y < inputArray.length; y++) {
hyperlinkBuilder.append(inputArray[y] + " ");
}
if(param.software.equals("MEDIAWIKI")) {
String hyperlink = "http://" + param.domain + "/index.php?search=" + hyperlinkBuilder.toString();
System.out.println("Searching for " + hyperlinkBuilder.toString() + " on the " + param.name;
player.addChatMessage("Searching for " + hyperlinkBuilder.toString() + " on the " + param.name;
BrowserHandler.browserInit(hyperlink.replace(" ", "+"), player);
System.out.println("Opening " + hyperlink.replace(" ", "+"));
// Keep track of how we exited the loop
foundMediaWikiKey = true;
break;
}
}
}
// When we exit, check to see how we did so.
if (!foundMediaWikiKey) {
// Last Resort
}
}
We usually do it like this where we search first and then put the code to handle the found one later.
I also lifted the one part out of the loop, since it didn't need to be in there. It could also go down in the "found" part of the code but I liked getting it out of the way to make the code more readable.
Also, the test for MEDIAWIKI is left in the loop (unlike my earlier version of this). Thanks to #paxdiablo for that. It is also a failing of some other answers here (as of right now).
StringBuilder hyperlinkBuilder = new StringBuilder(); // lift this out of the loop
for(int y = 1; y < inputArray.length; y++) {
hyperlinkBuilder.append(inputArray[y] + " ");
}
int found = -1;
for(int x = 0; x < keyList.size(); x++)
{
System.out.println("Starting the inside of the loop");
if((keyList.get(x)).equals(inputArray[0])) {
if((softwareList.get(x)).equals("MEDIAWIKI"))
found = x;
break;
}
}
}
if (found >= 0) {
int x = found;
//getWikiName = wikiNameArray[x]
//getWikiDomain = wikiDomainArray[x]
//getWikiSoftware = wikiSoftwareArray[x]
String hyperlink = "http://" + domainList.get(x) + "/index.php?search=" + hyperlinkBuilder.toString();
System.out.println("Searching for " + hyperlinkBuilder.toString() + " on the " + nameList.get(x));
player.addChatMessage("Searching for " + hyperlinkBuilder.toString() + " on the " + nameList.get(x));
BrowserHandler.browserInit(hyperlink.replace(" ", "+"), player);
System.out.println("Opening " + hyperlink.replace(" ", "+"));
} else {
//LAST RESORT ... fill in 'not found' code
}
I want my loop to go through ALL of the values in keyList before it
resorts the "last resort" - an else statement
else if(some condition)
{
if(x!=keylist.size()-1) // USE IT HERE
{ continue; }
//LAST RESORT
}

Comparing Sentences in Java

I would like to compare two sentences (sentences A and B), such that the program would output the changes made on sentence B from sentence A. For example:
sentence A: It's a lovely day today.
sentence B: It's a very lovely day today, isnt it?
Output: It's a [I:very] lovely day today [C:./,] [I:isnt it?]
where:
I = INSERTED,
C = CHANGED
PS: I havent started coding yet since I want to gather some of your ideas on how to best implement this case.
I have come up with below code and for this problem.
Conditions Not considered
Removed items from any of the list
First char difference
duplication of diff item
Please check and let me know if you have doubts.
public static void main(String[] args) {
String str1 = "It's a lovely day today.";
String str2 = "It's a very lovely day today, isnt it?";
StringBuilder builder = new StringBuilder();
StringBuilder added = new StringBuilder();
StringBuilder changed = new StringBuilder();
for (int i = 0; i < str1.length(); i++)
for (int j = 0; j < str2.length(); j++) {
if (str1.charAt(i) == str2.charAt(j)) {
if (added.length() > 0) {
builder.append("[I:" + added.toString() + "]");
added = new StringBuilder();
}
if (changed.length() > 0) {
changed.append("[C:" + changed.toString() + "]");
changed = new StringBuilder();
}
// skip as there is no difference.
builder.append(str1.charAt(i));
i++;
// check if index -1 chars are equal then there is
// difference start
} else if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
// check if end of line
if ((i + 1 == str1.length())
|| (str1.charAt(i + 1) == str2.charAt(j + 1))) {
changed.append(str1.charAt(i));
changed.append("/");
changed.append(str2.charAt(j));
j++;
// everything is added
if (i + 1 == str1.length()) {
while (j < str2.length() - 1)
added.append(str2.charAt(j++));
}
continue;
}
// Go until next equal found
while (!(str1.charAt(i) == str2.charAt(j))
&& j < str2.length() - 1) {
added.append(str2.charAt(j++));
}
j--;
}
}
if (changed.length() > 0) {
builder.append("[C:" + changed.toString() + "]");
}
if (added.length() > 0) {
builder.append("[I:" + added.toString() + "]");
}
System.out.println(builder.toString());
}
Output
It's a [I:very ]lovely day today[C:./,][I: isnt it]

Categories