The program allows the user to enter a phrase and converts it to ROT13, where each English letter entered, becomes the letter 13 places after it(A becomes N). My current code works when 1 character is entered, however I need it to run through the code the number of times there are characters. I've tried to put in a while loop at the beginning, but it doesn't seem to be working. Why is this?
import java.io.*;
public class J4_1_EncryptionErasetestCNewTry
{
public static void main (String [] args) throws IOException
{
BufferedReader myInput = new BufferedReader (new InputStreamReader (System.in));// Buffered Reader reads the number inputed
String key [] = {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"};
String keyA [] = {"N","O","P","Q","R","S","T","U","V","W","X","Y","Z","A","B","C","D","E","F","G","H","I","J","K","L","M"};
System.out.println("Enter a phrase: ");
String phrase = myInput.readLine();
int length = phrase.length();
int y = 0, i = 0, num = 0;
while (y <= length) {
String letter = Character.toString(phrase.charAt(y));
y++;
while(!(letter.equals(key[i]))){
i++;
}
num = i;
System.out.println(keyA[num]);
y++;
}
}
}
See comments on code.
public static void main(String[] args) {
BufferedReader myInput = new BufferedReader (new InputStreamReader (System.in));// Buffered Reader reads the number inputed
String key [] = {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"};
String keyA [] = {"N","O","P","Q","R","S","T","U","V","W","X","Y","Z","A","B","C","D","E","F","G","H","I","J","K","L","M"};
System.out.println("Enter a phrase: ");
String phrase = "";
try {
phrase = myInput.readLine();
} catch (IOException e) {
e.printStackTrace();
}
int length = phrase.length();
int y = 0, i = 0, num = 0;
while (y < length) { // This should be y < length. Otherwise, it would throw a StringIndexOutOfBoundsException.
i=0; // Re-initialize
String letter = Character.toString(phrase.charAt(y));
// y++; // Unecessary incremental
while(!(letter.equalsIgnoreCase(key[i]))){
i++;
}
num = i;
System.out.print(keyA[num]);
y++;
}
}
Although this doesn't answer your problem, it answers your intention:
public static String rot13(String s) {
String r = "";
for (byte b : s.getBytes())
r += (char)((b + 13 - 'A') % 26 + 'A');
return r;
}
Your code is far too complicated for what it's doing. Really, all the work can be done in one line. Use byte arithmetic rather than array lookups etc. Simple/less code is always the best approach.
Please no comments about inefficiencies etc. This is a basic implementation that works (tested). The reader is free to improve on it as an exercise.
You're code will most likely break in your inner while loop as you are not resetting the value of i. By not doing so your gonna hit StringIndexOutOfBounds. I would recommend initialising i in your outer while loop or better yet just move int i = 0; inside the outer while loop.
I have implemented it in a different way, but it works as you expect, only for uppercase as in your example:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;
public class WhileLoopIssue {
public static void main( String[] args ) throws IOException {
BufferedReader myInput = new BufferedReader( new InputStreamReader(
System.in ) );// Buffered Reader reads the
// number inputed
final List<String> letterList = Arrays.asList( "A", "B", "C", "D", "E",
"F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
"R", "S", "T", "U", "V", "W", "X", "Y", "Z" );
System.out.println( "Enter a phrase: " );
String phrase = myInput.readLine();
final String[] letters = phrase.split( "" ); // Split input phrase
final StringBuffer buffer = new StringBuffer(); // Variable to save letters. Could be a String as well.
for ( int i = 0; i < letters.length; i++ ) {
final int letterIndex = letterList.indexOf( letters[i] ); // Get the numeric value of the letter
if ( letterIndex < 0 ) // Skip iteration if not found. Maybe a lowercase, or an empty String
continue;
final int nextLetterIndex = 13 + letterIndex; // Actual value of the letter + 13
if ( nextLetterIndex > letterList.size() ) {
buffer.append( nextLetterIndex % letterList.size() ); // Actual value greater than the total number of letters in the alphabet, so we get the modulus for the letter
} else {
buffer.append( letterList.get( nextLetterIndex ) ); // Letter in the range, get it
}
}
System.out.println( buffer.toString() );
}
}
You need to reset i in each iteration. It may happen that first letter found toward the end of the array "key". Your code will find next input char there onward, I guess this is not what you want, and will not find that char and will throw SIOBException. I have changed the while loop, removed twice increment in variable y as well. Have a look
while (y < length) {
i = 0; //Every Time you want to search from start of the array
//so just reset the i.
String letter = Character.toString(phrase.charAt(y));
while(!(letter.equals(key[i]))){
i++;
}
num = i;
System.out.println(keyA[num]);
y++;
}
I am assuming what ever you enter as input is a phrase of ONLY upper-case alphabets, else you will come across the SIOBException as you you will not be able to locate that letter in your array.
Just on side note, instead of those arrays you should use some other data structures which are efficient for searching like hashmap. Your linear search across the array is not optimized.
Related
I have a program where I receive a long string in the format
characters$xxx,characters$xx,characters$xx, (....)
x is some digit of some integer with an arbitrary number of digits. The integer values are always contained within $ and ,.
I need to extract the integers into an integer array then print that array. The second part is easy, but how to extract those integers?
an example string: adsdfsh$1234,khjdfd$356,hsgadfsd$98,ghsdsk$4623,
the arraay should contain 1234, 356, 98, 4623
below is my basic logic
import java.util.Scanner;
class RandomStuff {
public static void main (String[]args){
Scanner keyboard = new Scanner(System.in);
String input = keyboard.next();
int count =0;
// counts number of $, because $ will always preceed an int in my string
for(int i=0;i<input.length();i++ ){
if (input.charAt(i)=='$')
count++;}
/* also I'm traversing the string twice here so my complexity is at least
o(2n) if someone knows how to reduce that, please tell me*/
int [] intlist = new int[count];
// fill the array
int arrayindex =0;
for (int i=0; i<input.length();i++){
if (input.charAt(i)=='$'){
/*insert all following characters as a single integer in intlist[arrayindex]
until we hit the character ','*/}
if (input.charAt(i)==','){
arrayindex++;
/*stop recording characters*/}
}
// i can print an array so I'll just omit the rest
keyboard.close();
}
You can use a regular expression with a positive lookbehind to find all consecutive sequences of digits preceded by a $ symbol. Matcher#results can be used to get all of the matches.
String str = "adsdfsh$1234,khjdfd$356,hsgadfsd$98,ghsdsk$4623";
int[] nums = Pattern.compile("(?<=\\$)\\d+").matcher(str).results()
.map(MatchResult::group)
.mapToInt(Integer::parseInt).toArray();
System.out.println(Arrays.toString(nums));
It can done like this
var digitStarts = new ArrayList<Integer>()
var digitsEnds = new ArrayList<Integer>()
// Get the start and end of each digit
for (int i=0; i<input.length();i++){
if(input[i] == '$' ) digitsStarts.add(i)
if(input[i] == ',') digitEnds.add(i)
}
// Get the digits as strings
var digitStrings = new ArrayList<String>()
for(int i=0;i<digitsStart.length; i++ ) {
digitsString.add(input.substring(digitsStarts[i]+1,digitEnds[i]))
}
// Convert to Int
var digits = new ArrayList<Int>
for(int i=0;i<digitString;i++) {
digits.add(Integer.valueOf(digitStrings[i]))
}
In a very simple way:
public static void main(String[] args) {
String str = "adsdfsh$1234,khjdfd$356,hsgadfsd$98,ghsdsk$4623";
String strArray[] = str.split(",");
int numbers[] = new int[strArray.length];
int j = 0;
for(String s : strArray) {
numbers[j++] = Integer.parseInt(s.substring(s.indexOf('$')+1));
}
for(j=0;j<numbers.length;j++)
System.out.print(numbers[j]+" ");
}
OUTPUT: 1234 356 98 4623
import java.util.Scanner;
public class CountVowel{
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
Getting the size of the array:
System.out.println("Type how many words will be typed: ");
int input = scan.nextInt();
Filling array with string values
String[] ar1 = new String[input];
for(int i = 0; i < ar1.length; i++){
System.out.println("Type the elements of array with words: ");
ar1[i] = scan.next();
}
Output of the program :
System.out.println( input + " words are typed and " +
countVowels(ar1) +
" of them contain more than 3 vowels.");
}
The method that counts vowels:
public static int countVowels(String[] ar1){ // this method counts
int a = 0;
String[] ar2 = new String[]{"a", "e", "i", "u", "y", "o"};
for(int i = 0; i < ar1.length; i++){
for(String s : ar2){
if(ar1[i].toLowerCase().contains(s)){
a++;
}
}
}
return a;
}
}
The method above is to check the vowels, but i dont know how to make it check if
there are more than 3 vowels.
Another solution with replaceAll method.
The main idea is to substract from word.length() the same word length without vowels. And check the difference.
public static int countVowels(String[] ar1){
int a = 0;
for (String word : ar1) {
int i = word.length() - word.toLowerCase().replaceAll("[aeyiuo]", "").length();
if (i >= 3) {
a++;
}
}
return a;
}
Or you can use matches() as #pkgajulapalli suggested. It can be quite concise with stream api:
long count = Arrays.stream(words)
.filter(s -> s.toLowerCase().matches("(.*[aeyiuo].*){3,}"))
.count();
public static int countVowels(String[] ar1) { // this method counts
int vowelPerWord = 0;
int totalWordsWithThreeVowels = 0;
char[] ar2 = new char[] { 'a', 'e', 'i', 'u', 'y', 'o' };
for (int i = 0; i < ar1.length; i++) {
vowelPerWord = 0;
for (int j = 0; j < ar1[i].length(); j++) {
for (int k = 0; k < ar2.length; k++) {
if (ar2[k] == (ar1[i].charAt(j))) {
vowelPerWord++;
}
}
}
if (vowelPerWord >= 3) {
totalWordsWithThreeVowels++;
}
}
return totalWordsWithThreeVowels;
}
EDIT
alright now i fixed the error and edited the variablenames to make a bit more sense. although this is O(n*m) i believe (where n is the number of strings and m is the number of char the longest string has) (not so good complexity) it gets the job done ar1 in this case is your input of strings, ar2 are just the vowels that exist.
so you go through every string in ar1 and set "vowelPerWord" to 0, go through every single char in every string and check if it is a vowel increase the vowelPerWord by 1. at the end, after you went through every char of that string you check if there were 3 or more vowels, if so increase the totalWordsWithThreeVowels, which at the end is returned.
What you need is an additional loop and count. Something like this:
// This method counts how many words have at least 3 vowels
public static int countVowels(String[] wordsArray){
int atLeastThreeVowelsCount = 0;
for(String word : wordsArray){
int vowelCount = 0;
for(String vowel : new String[]{ "a", "e", "i", "u", "y", "o" }){
if(word.toLowerCase().contains(vowel)){
vowelCount++;
}
}
if(vowelCount >= 3){
atLeastThreeVowelsCount++;
}
}
return atLeastThreeVowelsCount;
}
Try it online.
Note that I've also given the variables some more useful names, instead of ar1, s, etc. so it's easier to read what's going on.
You can use regex matching to find if a string contains any set of characters. For example, if you want to find if a string contains any of vowels, you can use:
String str = "yydyrf";
boolean contains = str.toLowerCase().matches(".*[aeiou].*");
System.out.println(contains);
EDIT:
So your code would look like:
public static int countVowels(String[] ar1) {
int a = 0;
String[] ar2 = new String[] { "a", "e", "i", "u", "y", "o" };
String pattern = ".*[" + String.join("", ar2) + "].*";
for (int i = 0; i < ar1.length; i++) {
if (ar1[i].matches(pattern)) {
a++;
}
}
return a;
}
You can use this:
public static int countVowels(String[] words) {
char[] chars = {'a', 'e', 'i', 'u', 'y', 'o'};
int wordsWith3Vowels = 0;
for (String word : words) {
int countedVowels = 0;
for (char s : chars) {
if (word.toLowerCase().indexOf(s) != -1) {
countedVowels++;
}
}
if (countedVowels >= 3) {
wordsWith3Vowels++;
}
}
return wordsWith3Vowels;
}
Which uses chars instead of Strings which is a tad faster
public static int countVowels(String[] ar1){ // this method counts
//Create hash map key = array string && value = vowels count
Map<String,Integer> mapVowels=new HashMap<String,Integer>();
int a = 0;
String[] ar2 = new String[]{"a", "e", "i", "u", "y", "o"};
for(int i = 0; i < ar1.length; i++){
for(String s : ar2){
if(ar1[i].toLowerCase().contains(s)){
//Check map string already has vowel count then increase by one
if(mapVowels.get(s)!=null) {
mapVowels.put(s,mapVowels.get(s)+1);
//After add the vowels count get actual count and check is it more than 3
if(mapVowels.get(s)>3)
a++;
}
else {
//If the vowels string new for map then add vowel count as 1 for first time
mapVowels.put(s,1);
}
}
}
}
return a;
}
Since java-8 you can now use Streams.
String[] values = {"AA","BC","CD","AE"};
boolean contains = Arrays.stream(values).anyMatch("s"::equals);
To check whether an array of int, double or long contains a value use IntStream, DoubleStream or LongStream respectively.
Example
int[] a = {1,2,3,4};
boolean contains = IntStream.of(a).anyMatch(x -> x == 4);
Well, this is my first time get here.
I'm trying to figure out the correct way to replace number into letter.
In this case, I need two steps.
First, convert letter to number. Second, restore number to word.
Words list: a = 1, b = 2, f = 6 and k = 11.
I have word: "b a f k"
So, for first step, it must be: "2 1 6 11"
Number "2 1 6 11" must be converted to "b a f k".
But, I failed at second step.
Code I've tried:
public class str_number {
public static void main(String[] args){
String word = "b a f k";
String number = word.replace("a", "1").replace("b","2").replace("f","6").replace("k","11");
System.out.println(word);
System.out.println(number);
System.out.println();
String text = number.replace("1", "a").replace("2","b").replace("6","f").replace("11","k");
System.out.println(number);
System.out.println(text);
}
}
Result:
b a f k
2 1 6 11
2 1 6 11
b a f aa
11 must be a word "k", but it's converted to "aa"
What is the right way to fix this?
Or do you have any other ways to convert letter to number and vice versa?
Thank you.
It would be good to write methods for conversion between number and letter format. I would write some code like this and use it generally instead of hard coding replace each time.
public class test {
static ArrayList <String> letter = new ArrayList<String> ();
static ArrayList <String> digit = new ArrayList<String> ();
public static void main(String[] args) {
createTable();
String test="b a f k";
String test1="2 1 6 11";
System.out.println(letterToDigit(test));
System.out.println(digitToLetter(test1));
}
public static void createTable()
{
//Create all your Letter to number Mapping here.
//Add all the letters and digits
letter.add("a");
digit.add("1");
letter.add("b");
digit.add("2");
letter.add("c");
digit.add("3");
letter.add("d");
digit.add("4");
letter.add("e");
digit.add("5");
letter.add("f");
digit.add("6");
letter.add("g");
digit.add("7");
letter.add("h");
digit.add("8");
letter.add("i");
digit.add("9");
letter.add("j");
digit.add("10");
letter.add("k");
digit.add("11");
letter.add("l");
digit.add("12");
letter.add("m");
digit.add("13");
letter.add("n");
digit.add("14");
letter.add("o");
digit.add("14");
letter.add("p");
digit.add("15");
//Carry so on till Z
}
public static String letterToDigit(String input)
{
String[] individual = input.split(" ");
String result="";
for(int i=0;i<individual.length;i++){
if(letter.contains(individual[i])){
result+=Integer.toString(letter.indexOf(individual[i])+1)+ " ";
}
}
return result;
}
public static String digitToLetter(String input)
{
String[] individual = input.split(" ");
String result="";
for(int i=0;i<individual.length;i++){
if(digit.contains(individual[i])){
result+=letter.get(digit.indexOf(individual[i])) + " ";
}
}
return result;
}
}
I would actually not use replace in this case.
A more generic solution would be to simply convert it to a char and subtract the char a from it.
int n = word.charAt(0) - 'a' + 1;
This should return an int with the value you are looking for.
If you want this to be an string you can easily do
String s = Integer.parseInt(word.charAt(0) - 'a' + 1);
And as in your case you are doing a whole string looping through the length of it and changing all would give you the result
String s = "";
for(int i = 0; i < word.length(); i++) {
if(s.charAt(i) != ' ') {
s = s + Integer.toString(word.charAt(i) - 'a' + 1) + " ";
}
}
and then if you want this back to an String with letters instead
String text = "";
int temp = 0;
for(int i = 0; i < s.length(); i++) {
if(s.charAt(i) == ' ') {
text = text + String.valueOf((char) (temp + 'a' - 1));
temp = 0;
} else if {
temp = (temp*10)+Character.getNumericValue(s.charAt(i));
}
}
You can just reverse the replacement:
String text = number.replace("11","k").replace("2","b").replace("6","f").replace("1","a");
Simplest solution IMO.
When adding other numbers, first replace these with two digits, then these with one.
Replace this:
String text = number.replace("1", "a").replace("2","b").replace("6","f").replace("11","k");
By this:
String text = number.replace("11","k").replace("1", "a").replace("2","b").replace("6","f");
Right now, the first replace you're doing: ("1", "a")
is invalidating the last one: ("11","k")
I think you would need to store the number as an array of ints. Otherwise, there is no way of knowing if 11 is aa or k. I would create a Map and then loop over the characters in the String. You could have one map for char-to-int and one for int-to-char.
Map<Character,Integer> charToIntMap = new HashMap<Character,Integer>();
charToIntMap.put('a',1);
charToIntMap.put('b',2);
charToIntMap.put('f',6);
charToIntMap.put('k',11);
Map<Integer,Character> intToCharMap = new HashMap<Integer,Character>();
intToCharMap.put(1,'a');
intToCharMap.put(2,'b');
intToCharMap.put(6,'f');
intToCharMap.put(11,'k');
String testStr = "abfk";
int[] nbrs = new int[testStr.length()];
for(int i = 0; i< testStr.length(); i++ ){
nbrs[i] = charToIntMap.get(testStr.charAt(i));
}
StringBuilder sb = new StringBuilder();
for(int num : nbrs){
sb.append(num);
}
System.out.println(sb.toString());
//Reverse
sb = new StringBuilder();
for(int i=0; i<nbrs.length; i++){
sb.append(intToCharMap.get(nbrs[i]));
}
System.out.println(sb.toString());
This failed because the replace("1", "a") replaced both 1s with a characters. The quickest fix is to perform the replace of all the double-digit numbers first, so there are no more double-digit numbers left when the single-digit numbers get replaced.
String text = number.replace("11","k").replace("1", "a").
replace("2","b").replace("6","f");
okay basically im wanting to separate the elements in a string from int and char values while remaining in the array, but to be honest that last parts not a requirement, if i need to separate the values into two different arrays then so be it, id just like to keep them together for neatness. this is my input:
5,4,A
6,3,A
8,7,B
7,6,B
5,2,A
9,7,B
now the code i have so far does generally what i want it to do, but not completely
here is the output i have managed to produce with my code but here is where im stuck
54A
63A
87B
76B
52A
97B
here is where the fun part is, i need to take the numbers and the character values and separate them so i can use them in a comparison/math formula.
basically i need this
int 5, 4;
char 'A';
but of course stored in the array that they are in.
Here is the code i have come up with so far.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
public class dataminingp1
{
String[] data = new String[100];
String line;
public void readf() throws IOException
{
FileReader fr = new FileReader("C:\\input.txt");
BufferedReader br = new BufferedReader(fr);
int i = 0;
while ((line = br.readLine()) != null)
{
data[i] = line;
System.out.println(data[i]);
i++;
}
br.close();
System.out.println("Data length: "+data.length);
String[][] root;
List<String> lines = Files.readAllLines(Paths.get("input.txt"), StandardCharsets.UTF_8);
root = new String[lines.size()][];
lines.removeAll(Arrays.asList("", null)); // <- remove empty lines
for(int a =0; a<lines.size(); a++)
{
root[a] = lines.get(a).split(" ");
}
String changedlines;
for(int c = 0; c < lines.size(); c++)
{
changedlines = lines.get(c).replace(',', ' '); // remove all commas
lines.set(c, changedlines);// Set the 0th index in the lines with the changedLine
changedlines = lines.get(c).replaceAll(" ", ""); // remove all white/null spaces
lines.set(c, changedlines);
changedlines = lines.get(c).trim(); // remove all null spaces before and after the strings
lines.set(c, changedlines);
System.out.println(lines.get(c));
}
}
public static void main(String[] args) throws IOException
{
dataminingp1 sarray = new dataminingp1();
sarray.readf();
}
}
i would like to do this as easily as possible because im not to incredibly far along with java but i am learning so if need be i can manage with a difficult process. Thank you in advance for any at all help you may give. Really starting to love java as a language thanks to its simplicity.
This is an addition to my question to clear up any confusion.
what i want to do is take the values stored in the string array that i have in the code/ input.txt and parse those into different data types, like char for character and int for integer. but im not sure how to do that currently so what im asking is, is there a way to parse these values all at the same time with out having to split them into different arrays cause im not sure how id do that since it would be crazy to go through the input file and find exactly where every char starts and every int starts, i hope this cleared things up a bit.
Here is something you could do:
int i = 0;
for (i=0; i<list.get(0).size(); i++) {
try {
Integer.parseInt(list.get(0).substring(i, i+1));
// This is a number
numbers.add(list.get(0).substring(i, i+1));
} catch (NumberFormatException e) {
// This is not a number
letters.add(list.get(0).substring(i, i+1));
}
}
When the character is not a number, it will throw a NumberFormatException, so, you know it is a letter.
for(int c = 0; c < lines.size(); c++){
String[] chars = lines.get(c).split(",");
String changedLines = "int "+ chars[0] + ", " + chars[1] + ";\nchar '" + chars[0] + "';";
lines.set(c, changedlines);
System.out.println(lines.get(c));
}
It is very easy, if your input format is standartized like this. As long as you dont specify more (like can have more than 3 variables in one row, or char can be in any column, not only just third, the easiest approach is this :
String line = "5,4,A";
String[] array = line.split(",");
int a = Integer.valueOf(array[0]);
int b = Integer.valueOf(array[1]);
char c = array[2].charAt(0);
Maybe something like this will help?
List<Integer> getIntsFromArray(String[] tokens) {
List<Integer> ints = new ArrayList<Integer>();
for (String token : tokens) {
try {
ints.add(Integer.parseInt(token));
} catch (NumberFormatException nfe) {
// ...
}
}
return ints;
}
This will only grab the integers, but maybe you could hack it around a bit to do what you want :p
List<String> lines = Files.readAllLines(Paths.get("input.txt"), StandardCharsets.UTF_8);
String[][] root = new String[lines.size()][];
for (int a = 0; a < lines.size(); a++) {
root[a] = lines.get(a).split(","); // Just changed the split condition to split on comma
}
Your root array now has all the data in the 2d array format where each row represents the each record/line from the input and each column has the data required(look below).
5 4 A
6 3 A
8 7 B
7 6 B
5 2 A
9 7 B
You can now traverse the array where you know that first 2 columns of each row are the numbers you need and the last column is the character.
Try this way by using getNumericValue() and isDigit methods. This might also work,
String myStr = "54A";
boolean checkVal;
List<Integer> myInt = new ArrayList<Integer>();
List<Character> myChar = new ArrayList<Character>();
for (int i = 0; i < myStr.length(); i++) {
char c = myStr.charAt(i);
checkVal = Character.isDigit(c);
if(checkVal == true){
myInt.add(Character.getNumericValue(c));
}else{
myChar.add(c);
}
}
System.out.println(myInt);
System.out.println(myChar);
Also check, checking character properties
Can you help? Get error Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: -1 when run this program. How to fix rhis? StringBuffer and StringTokenizer is necessary. Also, how can it be done simplier?
import java.util.StringTokenizer;
public class main {
public static int i, n;
public static boolean orly = false;
public static StringBuffer input, tokenStr;
public static StringTokenizer out;
public static char aChar;
public static void main(String[] args) {
input = new StringBuffer("some text");
System.out.println("Начальная строка - " + input.toString());
input = new StringBuffer(input.toString().replaceAll("[^a-z A-Z А-Я а-я]", ""));
if (input.toString().trim().length() != 0) {
out = new StringTokenizer(input.toString());
System.out.println("Форматированая строка - " + input.toString());
n = (out.countTokens());
String[] charSet = { "a", "e", "o", "u", "y" };
for (i = 0; i <= n - 1; i++) {
tokenStr = new StringBuffer(out.nextToken());
aChar = (tokenStr.charAt(0));
String firstchar = tokenStr.toString().substring(0,1);
if (tokenStr.length() > 1) {
for (int i = 0; i <= charSet.length-1; i++) {
if ((!firstchar.equals(charSet[i])) || (!firstchar.toUpperCase().equals(charSet[i]))) {
input.delete(input.indexOf(tokenStr.toString()),input.indexOf(tokenStr.toString())+ tokenStr.length() + 1);
}
}
} else {
input.deleteCharAt(input.indexOf(tokenStr.toString()));
}
}
}
}
}
for (i = 0; i <= n - 1; i++) {
//stuff
if (tokenStr.length() > 1) {
for (int i = 0; i <= charSet.length-1; i++) {
//stuff
}
}
}
in the first for loop, you have a temporary variable i that exists only inside those curly braces. However, in your second for loop, you're creating another variable i. This i will overwrite the first one yet will still be incremented in both loops. You'd best rename the second one to j or something.
Additionally, in:
input.delete(input.indexOf(tokenStr.toString()),input.indexOf(tokenStr.toString())+ tokenStr.length() + 1);
What happens if tokenStr is not in input? Then indexOf will return -1 (predefined behaviour), which is causing this particular Exception.
So.. I just need to delete all words in the String that not starts from "a", "e", "o", "u", "y", "i" and words with one char (like I, a). And create String with words that stay
Consider a different way. Rather than removing the unwanted words from the output StringBuffer, try adding wanted words to the output buffer as you find them. You can describe this logic to walking along your input string and writing down the words you want as you find them.
StringBuffer outString = new StringBuffer();
StringTokenizer st = new StringTokenizer(input.toString());
while(st.hasMoreTokens()){
String currentToken = (String)st.nextToken();
if(currentToken.length() < 2){
continue;
}
for(int i = 0; i < charSet.length; i++){
if(charSet[i] == currentToken.charAt(0)){
outString.append(currentToken);
break;
}
}
}