this is code I am using to translate some text to English from pig Latin and vice versa. Except the fromPig method does not seem to be working correctly.
Expected output: "java is a wonderful programming language, and object oriented programming is the best thing after sliced bread."
Got output: "avajavajay isyisyay ayay onderfulwonderfulway ogrammingprogrammingpray..."
So you can see that the words are inside but I need to get rid of the other parts on the ends of the word. Please try to provide code if you can fixing my mistake.
public class PigLatin {
public String fromPig(String pigLatin) {
String res="";
String[] data=pigLatin.split(" ");
for(String word : data)
res += toEnglishWord(word) + " ";
return res;
}
private String toEnglishWord(String word) {
char punc=0;
for(int i=0;i<word.length();i++) {
if(word.charAt(i)=='.'||word.charAt(i)==','||word.charAt(i)==';'||word.charAt(i)=='!') {
punc=word.charAt(i);
break;
}
}
word=word.replace(punc + "","");
String[] data=word.split("-");
String firstPart=data[0];
String lastPart=data[0];
if(lastPart.equals("yay"))
return firstPart + punc ;
else {
lastPart=lastPart.replace("ay","");
return(lastPart+firstPart+punc);
}
}
}
This is the class that needs to execute the sentences.
public class Convert {
public static void main(String args []) {
PigLatin demo=new PigLatin();
String inEnglish="Now is the winter of our discontent " +
"Made glorious summer by this sun of York; " +
"And all the clouds that lour'd upon our house " +
"In the deep bosom of the ocean buried.";
String inPigLatin="avajay isyay ayay onderfulway ogrammingpray " +
"anguagelay, andyay objectyay orientedyay ogrammingpray " +
"isyay hetay estbay ingthay afteryay icedslay eadbray.";
System.out.println(demo.toPig(inEnglish));
System.out.println(demo.fromPig(inPigLatin));
}
}
Basically the english sentence needs to be converted to pig latin and the pig latin sentence needs to be converted to english.
English to piglatin is being done correctly. But piglatin to english is not.
Address the following problems:
Convert the text to a single case (e.g. lowercase) because you are comparing with only lowercase vowels.
The code inside your toEnglishWord is not correct. Change it as follows:
private String toEnglishWord(String word) {
char punc = 0;
for (int i = 0; i < word.length(); i++) {
if (word.charAt(i) == '.' || word.charAt(i) == ',' || word.charAt(i) == ';' || word.charAt(i) == '!') {
punc = word.charAt(i);
break;
}
}
// Trim the word, and remove all punctuation chars
word = word.trim().replaceAll("[\\.,;!]", "");
String english = "";
// If the word ends with 'yay', remove 'yay' from its end. Otherwise, if the
// word ends with 'ay', form the word as (3rd last letter + characters from
// beginning till the 4th last character). Also, add the punctuation at the end
if (word.length() > 2 && word.substring(word.length() - 3).equals("yay")) {
english = word.substring(0, word.length() - 3) + String.valueOf(punc);
} else if (word.length() > 3 && word.substring(word.length() - 2).equals("ay")) {
english = word.substring(word.length() - 3, word.length() - 2) + word.substring(0, word.length() - 3)
+ String.valueOf(punc);
}
return english;
}
Demo:
class PigLatin {
public String toPig(String english) {
String res = "";
String[] data = english.toLowerCase().split(" ");
for (String word : data)
res += toPigWord(word) + " ";
return res;
}
public String fromPig(String pigLatin) {
String res = "";
String[] data = pigLatin.toLowerCase().split(" ");
for (String word : data)
res += toEnglishWord(word) + " ";
return res;
}
private String toPigWord(String word) {
char punc = 0;
for (int i = 0; i < word.length(); i++) {
if (word.charAt(i) == '.' || word.charAt(i) == ',' || word.charAt(i) == ';' || word.charAt(i) == '!') {
punc = word.charAt(i);
break;
}
}
word = word.replace(punc + "", "");
if (isFirstLetterVowel(word))
return (word + "yay" + punc);
else {
int indexVowel = indexOfFirstVowel(word);
String after = word.substring(indexVowel);
String before = word.substring(0, indexVowel);
return (after + before + "ay" + punc);
}
}
private String toEnglishWord(String word) {
char punc = 0;
for (int i = 0; i < word.length(); i++) {
if (word.charAt(i) == '.' || word.charAt(i) == ',' || word.charAt(i) == ';' || word.charAt(i) == '!') {
punc = word.charAt(i);
break;
}
}
// Trim the word, and remove all punctuation chars
word = word.trim().replaceAll("[\\.,;!]", "");
String english = "";
// If the word ends with 'yay', remove 'yay' from its end. Otherwise, if the
// word ends with 'ay' and form the word as (3rd last letter + characters from
// beginning to the 4th last character). Also, add the punctuation at the end
if (word.length() > 2 && word.substring(word.length() - 3).equals("yay")) {
english = word.substring(0, word.length() - 3) + String.valueOf(punc);
} else if (word.length() > 3 && word.substring(word.length() - 2).equals("ay")) {
english = word.substring(word.length() - 3, word.length() - 2) + word.substring(0, word.length() - 3)
+ String.valueOf(punc);
}
return english;
}
private boolean isFirstLetterVowel(String word) {
String temp = word.toLowerCase();
return (temp.charAt(0) == 'a' || temp.charAt(0) == 'e' || temp.charAt(0) == 'i' || temp.charAt(0) == 'o'
|| temp.charAt(0) == 'u');
}
private int indexOfFirstVowel(String word) {
int index = 0;
String temp = word.toLowerCase();
for (int i = 0; i < temp.length(); i++) {
if (temp.charAt(i) == 'a' || temp.charAt(i) == 'e' || temp.charAt(i) == 'i' || temp.charAt(i) == 'o'
|| temp.charAt(i) == 'u') {
index = i;
break;
}
}
return index;
}
}
class Main {
public static void main(String[] args) {
PigLatin pigLatin = new PigLatin();
String str = "hello world! good morning! honesty is a good policy.";
String strToPigLatin = pigLatin.toPig(str);
System.out.println(strToPigLatin);
System.out.println(pigLatin.fromPig(strToPigLatin));
}
}
Output:
ellohay orldway! oodgay orningmay! onestyhay isyay ayay oodgay olicypay.
hello world! good morning! honesty is a good policy.
Note: With the current logic, there is no way to convert a word like ogrammingpray (which is the piglatin of programming) back to programming.
It's impossible to convert Pig Latin to English just like that - you need a human, a program with access to a database of words, or a neural net or something that's been trained on a database of words. Without that, you will only be convert words back to English if they originally started with a vowel or their first letter was a consonant and their second letter was a vowel. Otherwise, there is literally no way for a machine to tell where the word originally ended.
For that reason, you need to make a method that outputs a List<String> like this:
public static List<String> allPossibleSentences(String inPigLatin) {
List<String> pigWords = Arrays.asList(inPigLatin.split("\\s"));
//You can also use a method reference here
List<List<String>> possSentences = cartesianProduct(pigWords.stream().map(word -> possibleEnglishWords(word)).collect(Collectors.toList()));
return possSentences.stream().map(words -> String.join(" ", words)).collect(Collectors.toList());
}
But since you need a fromPig method in your code, you can write it like this:
public static String fromPig(String inPigLatin) {
return allPossibleSentences(inPigLatin).get(0);
}
This is overpowered, compared to the answer by Arvind Kumar Avinash, since it generates all permutations, but I feel it will be more useful if you have the most likely case and all possible sentences.
Example main method
public static void main(String[] args) {
String inPigLatin="avajay isyay ayay onderfulway ogrammingpray " +
"anguagelay andyay objectyay orientedyay ogrammingpray " +
"isyay hetay estbay ingthay afteryay icedslay eadbray";
System.out.println(fromPig(inPigLatin));
inPigLatin = "icedslay eadbray";
System.out.println("\nExpected = sliced bread, gotten = " + fromPig(inPigLatin));
System.out.println(String.join("\n", allPossibleSentences(inPigLatin)));
}
Example output
java is a wonderful rogrammingp language and object oriented rogrammingp is the best hingt after liceds readb
Expected = sliced bread, gotten = liceds readb
liceds readb
liceds bread
liceds dbrea
sliced readb
sliced bread //Here you have the right answer, but your method has no way to confirm that
sliced dbrea
dslice readb
dslice bread
dslice dbrea
Your PigLatin class now
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.stream.Collectors;
class PigLatin {
//Put your toPig and toPigWord methods here (I couldn't find them)
public static String fromPig(String inPigLatin) {
return allPossibleSentences(inPigLatin).get(0);
}
/* Methods that above code relies on */
private static List<String> possibleEnglishWords(String word) {
List<String> possibilities = new ArrayList<>();
if (word.matches(".*yay$")) {
possibilities.add(word.substring(0, word.length() - 3));
return possibilities;
}
//Remove the pig latin part
word = word.substring(0, word.length() - 2);
for (int i = word.length() - 1; i >= 0; i --) {
if (isVowel(word.charAt(i))) break;
if (word == "anguagel") System.out.println("char = " + word.charAt(i));
possibilities.add(word.substring(i) + word.substring(0, i));
}
return possibilities;
}
//Put all the words together
public static List<List<String>> cartesianProduct(List<List<String>> possWordArr) {
if (possWordArr.size() == 1) {
List<List<String>> possSentencesAsWords = new ArrayList<>();
possSentencesAsWords.add(possWordArr.get(0));
return possSentencesAsWords;
}
return _cartesianProduct(0, possWordArr);
}
//Helper method
private static List<List<String>> _cartesianProduct(int index, List<List<String>> possWordArr) {
List<List<String>> ret = new ArrayList<>();
if (index == possWordArr.size()) {
ret.add(new ArrayList<>());
} else {
for (String word : possWordArr.get(index)) {
for (List<String> words : _cartesianProduct(index + 1, possWordArr)) {
words.add(0, word);
ret.add(words);
}
}
}
return ret;
}
private static boolean isVowel(char c) {
c = toUppercase(c);
switch (c) {
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
return true;
default:
return false;
}
}
private static char toUppercase(char c) {
if (c >= 'a') return (char) (((char) (c - 'a')) + 'A');
else return c;
}
}
Related
I'm creating a program that will count the number of letters, vowels and consonants from what user put into using Scanner.
Here's my code:
'''
static String phrase;
static int vowel = 0;
static int consonant = 0;
static String reverse = "";
public static void countChar() {
System.out.println("\nNumber of characters: " + phrase.length());
}
public static void countVowelCons() {
phrase = phrase.toLowerCase();
for (int i = 0; i < phrase.length(); i++) {
if (phrase.charAt(i) == 'a' || phrase.charAt(i) == 'e' || phrase.charAt(i) == 'i' || phrase.charAt(i) == 'o'
|| phrase.charAt(i) == 'u') {
vowel++;
} else if (phrase.charAt(i) >= 'a' && phrase.charAt(i) <= 'z') {
consonant++;
}
}
System.out.println("Number of vowels: " + vowel);
System.out.println("Number of consonants: " + consonant);
}
public static void reverseString() {
for (int i = phrase.length() - 1; i >= 0; i--) {
reverse += phrase.charAt(i);
}
System.out.println(reverse);
}
'''
In the reverseString() method, how can I make the reversed String get trimmed or make the last letter deleted in a loop until all what's left is a single letter.
For example:
User inputs "qwertyuiop".
What should be the output is something like this:
poiuytrewq poiuytrew poiuytre poiuytr poiuyt poiuy poiu poi po p
How can I make it done like that? Please help thanks alot!
'''
public static void reverseString() {
for (int i = phrase.length() - 1; i >= 0; i--) {
reverse += phrase.charAt(i);
}
System.out.println(reverse);
'''
public static void reverseString() {
StringBuilder reverseStr = new StringBuilder();
for (int i = phrase.length() - 1; i >= 0; i--) {
reverseStr.append(phrase.charAt(i));
}
reverse = reverseStr.toString();
System.out.println(reverse);
}
// OR You can use inbuild method reverse() of StringBuilder
public static void reverseString() {
StringBuilder reverseStr = new StringBuilder(phrase);
reverse = reverseStr.reverse().toString();
System.out.println(reverse);
}
Sometimes rather than fixing code, you find an easier way:
vowel = phrase.replaceAll("(?i)[^aeiou]", "").length();
consonant = phrase.replaceAll("(?i)[^b-z&&[^eiou]]", "").length();
reverse = new StringBuilder(phrase).reverse().toString();
See live demo.
The character counts work by replacing with blank (ie "deleting") characters that aren't the type being counted and using the length of the resulting string.
Reversing uses functionality provided by the StringBuilder built-in class.
There are 3 rules in the string:
It contains either word or group (enclosed by parentheses), and group can be nested;
If there is a space between word or group, those words or groups should append with "+".
For example:
"a b" needs to be "+a +b"
"a (b c)" needs to be "+a +(+b +c)"
If there is a | between word or group, those words or groups should be surround with parentheses.
For example:
"a|b" needs to be "(a b)"
"a|b|c" needs to be "(a b c)"
Consider all the rules, here is another example:
"aa|bb|(cc|(ff gg)) hh" needs to be "+(aa bb (cc (+ff +gg))) +hh"
I have tried to use regex, stack and recursive descent parser logic, but still cannot fully solve the problem.
Could anyone please share the logic or pseudo code on this problem?
New edited:
One more important rule: vertical bar has higher precedence.
For example:
aa|bb hh cc|dd (a|b) needs to be +(aa bb) +hh +(cc dd) +((a b))
(aa dd)|bb|cc (ee ff)|(gg hh) needs to be +((+aa +dd) bb cc) +((+ee +ff) (+gg +hh))
New edited:
To solve the precedence problem, I find a way to add the parentheses before calling Sunil Dabburi's methods.
For example:
aa|bb hh cc|dd (a|b) will be (aa|bb) hh (cc|dd) (a|b)
(aa dd)|bb|cc (ee ff)|(gg hh) will be ((aa dd)|bb|cc) ((ee ff)|(gg hh))
Since the performance is not a big concern to my application, this way at least make it work for me. I guess the JavaCC tool may solve this problem beautifully. Hope someone else can continue to discuss and contribute this problem.
Here is my attempt. Based on your examples and a few that I came up with I believe it is correct under the rules. I solved this by breaking the problem up into 2 parts.
Solving the case where I assume the string only contains words or is a group with only words.
Solving words and groups by substituting child groups out, use the 1) part and recursively repeating 2) with the child groups.
private String transformString(String input) {
Stack<Pair<Integer, String>> childParams = new Stack<>();
String parsedInput = input;
int nextInt = Integer.MAX_VALUE;
Pattern pattern = Pattern.compile("\\((\\w|\\|| )+\\)");
Matcher matcher = pattern.matcher(parsedInput);
while (matcher.find()) {
nextInt--;
parsedInput = matcher.replaceFirst(String.valueOf(nextInt));
String childParam = matcher.group();
childParams.add(Pair.of(nextInt, childParam));
matcher = pattern.matcher(parsedInput);
}
parsedInput = transformBasic(parsedInput);
while (!childParams.empty()) {
Pair<Integer, String> childGroup = childParams.pop();
parsedInput = parsedInput.replace(childGroup.fst.toString(), transformBasic(childGroup.snd));
}
return parsedInput;
}
// Transform basic only handles strings that contain words. This allows us to simplify the problem
// and not have to worry about child groups or nested groups.
private String transformBasic(String input) {
String transformedBasic = input;
if (input.startsWith("(")) {
transformedBasic = input.substring(1, input.length() - 1);
}
// Append + in front of each word if there are multiple words.
if (transformedBasic.contains(" ")) {
transformedBasic = transformedBasic.replaceAll("( )|^", "$1+");
}
// Surround all words containing | with parenthesis.
transformedBasic = transformedBasic.replaceAll("([\\w]+\\|[\\w|]*[\\w]+)", "($1)");
// Replace pipes with spaces.
transformedBasic = transformedBasic.replace("|", " ");
if (input.startsWith("(") && !transformedBasic.startsWith("(")) {
transformedBasic = "(" + transformedBasic + ")";
}
return transformedBasic;
}
Verified with the following test cases:
#ParameterizedTest
#CsvSource({
"a b,+a +b",
"a (b c),+a +(+b +c)",
"a|b,(a b)",
"a|b|c,(a b c)",
"aa|bb|(cc|(ff gg)) hh,+(aa bb (cc (+ff +gg))) +hh",
"(aa(bb(cc|ee)|ff) gg),(+aa(bb(cc ee) ff) +gg)",
"(a b),(+a +b)",
"(a(c|d) b),(+a(c d) +b)",
"bb(cc|ee),bb(cc ee)",
"((a|b) (a b)|b (c|d)|e),(+(a b) +((+a +b) b) +((c d) e))"
})
void testTransformString(String input, String output) {
Assertions.assertEquals(output, transformString(input));
}
#ParameterizedTest
#CsvSource({
"a b,+a +b",
"a b c,+a +b +c",
"a|b,(a b)",
"(a b),(+a +b)",
"(a|b),(a b)",
"a|b|c,(a b c)",
"(aa|bb cc|dd),(+(aa bb) +(cc dd))",
"(aa|bb|ee cc|dd),(+(aa bb ee) +(cc dd))",
"aa|bb|cc|ff gg hh,+(aa bb cc ff) +gg +hh"
})
void testTransformBasic(String input, String output) {
Assertions.assertEquals(output, transformBasic(input));
}
I tried to solve the problem. Not sure if it works in all cases. Verified with the inputs given in the question and it worked fine.
We need to format the pipes first. That will help add necessary parentheses and spacing.
The spaces generated as part of pipe processing can interfere with actual spaces that are available in our expression. So used $ symbol to mask them.
To process spaces, its tricky as parantheses need to be processed individually. So the approach I am following is to find a set of parantheses starting from outside and going inside.
So typically we have <left_part><parantheses_code><right_part>. Now left_part can be empty, similary right_part can be empty. we need to handle such cases.
Also, if the right_part starts with a space, we need to add '+' to left_part as per space requirement.
NOTE: I am not sure what's expected of (a|b). If the result should be ((a b)) or (a b). I am going with ((a b)) purely by the definition of it.
Now here is the working code:
public class Test {
public static void main(String[] args) {
String input = "aa|bb hh cc|dd (a|b)";
String result = formatSpaces(formatPipes(input)).replaceAll("\\$", " ");
System.out.println(result);
}
private static String formatPipes(String input) {
while (true) {
char[] chars = input.toCharArray();
int pIndex = input.indexOf("|");
if (pIndex == -1) {
return input;
}
input = input.substring(0, pIndex) + '$' + input.substring(pIndex + 1);
int first = pIndex - 1;
int closeParenthesesCount = 0;
while (first >= 0) {
if (chars[first] == ')') {
closeParenthesesCount++;
}
if (chars[first] == '(') {
if (closeParenthesesCount > 0) {
closeParenthesesCount--;
}
}
if (chars[first] == ' ') {
if (closeParenthesesCount == 0) {
break;
}
}
first--;
}
String result;
if (first > 0) {
result = input.substring(0, first + 1) + "(";
} else {
result = "(";
}
int last = pIndex + 1;
int openParenthesesCount = 0;
while (last <= input.length() - 1) {
if (chars[last] == '(') {
openParenthesesCount++;
}
if (chars[last] == ')') {
if (openParenthesesCount > 0) {
openParenthesesCount--;
}
}
if (chars[last] == ' ') {
if (openParenthesesCount == 0) {
break;
}
}
last++;
}
if (last >= input.length() - 1) {
result = result + input.substring(first + 1) + ")";
} else {
result = result + input.substring(first + 1, last) + ")" + input.substring(last);
}
input = result;
}
}
private static String formatSpaces(String input) {
if (input.isEmpty()) {
return "";
}
int startIndex = input.indexOf("(");
if (startIndex == -1) {
if (input.contains(" ")) {
String result = input.replaceAll(" ", " +");
if (!result.trim().startsWith("+")) {
result = '+' + result;
}
return result;
} else {
return input;
}
}
int endIndex = startIndex + matchingCloseParenthesesIndex(input.substring(startIndex));
if (endIndex == -1) {
System.out.println("Invalid input!!!");
return "";
}
String first = "";
String last = "";
if (startIndex > 0) {
first = input.substring(0, startIndex);
}
if (endIndex < input.length() - 1) {
last = input.substring(endIndex + 1);
}
String result = formatSpaces(first);
String parenthesesStr = input.substring(startIndex + 1, endIndex);
if (last.startsWith(" ") && first.isEmpty()) {
result = result + "+";
}
result = result + "("
+ formatSpaces(parenthesesStr)
+ ")"
+ formatSpaces(last);
return result;
}
private static int matchingCloseParenthesesIndex(String input) {
int counter = 1;
char[] chars = input.toCharArray();
for (int i = 1; i < chars.length; i++) {
char ch = chars[i];
if (ch == '(') {
counter++;
} else if (ch == ')') {
counter--;
}
if (counter == 0) {
return i;
}
}
return -1;
}
}
This is an interview question from
http://www.glassdoor.com/Interview/Indeed-Software-Engineer-Interview-Questions-EI_IE100561.0,6_KO7,24.htm , specifically, the problem
"The asked me a method that took in a string and return words up to the max length. There could be any amount of spaces which made it a little tricky "
Here is my solution(with test case)
public class MaxLength {
public static void main(String[] args) {
List<String> allWords = maxWords("Jasmine has no love for chris", 2);
for(String word: allWords){
System.out.println(word);
}
}
public static List<String> maxWords(String sentence, int length) {
String[] words = sentence.trim().split("\\s+");
List<String> list = new ArrayList<String>();
for(String word: words) {
if(word.length() <= length) {
list.add(word);
}
}
return list;
}
The test ran fine and i got my expected output - no. However during an actual interview, I think the interviewer doesn't expect you to know this regular expression off the top of your head (I didn't had to find it from How do I split a string with any whitespace chars as delimiters?)
Is there another approach to this problem without using regular expressions?
Try:
public static List<String> maxWords(String sentence, int length) {
List<String> list = new ArrayList<String>();
String tmp = sentence;
while (tmp.indexOf(" ") != -1) {
String word = tmp.substring(0,tmp.indexOf(" "));
tmp = tmp.substring(tmp.indexOf(" ")+1);
if(word.length() <= length) {
list.add(word);
}
}
return list;
}
You could use the StringTokenizer.
Another, maybe more lengthy approach would be to iterate over the string and use the methods provided by the Character class (Character.isWhiteSpace(char c)) and break the string accordingly.
Well, you could try something like this :
Doesn't create many subStrings() just creates subStrings of "matched" Strings
public class Test {
public static void main(String[] args) {
String s = "Jasmine has no love for chris";
s=s.trim();
List<String> ls = getMaxLength(s, 3);
for (String str : ls) {
System.out.println(str);
}
}
static List<String> getMaxLength(String s, int length) {
List<String> ls = new ArrayList<String>();
int i = 0;
if (s.charAt(i + length) == ' ' || i + length == s.length()) { // search if first word matches your criterion.
for (i = 1; i < length; i++) { // check for whitespace between 0 and length
if (s.charAt(i) == ' ') {
i = length;
break;
}
if (i == length - 1)
ls.add(s.substring(0, length));
}
}
for (i = length; i < s.length(); i++) {// start search from second word..
if (s.charAt(i - 1) == ' ' && i + length < s.length() // if char at length is space or end of String, make sure the char before the current char is a space.
&& (s.charAt(i + length) == ' ' || i + length == s.length())) {
for (int j = i; j < i + length; j++) {
if (s.charAt(j) == ' ') {
i = i + length;
break;
}
if (j == i + length - 1) {
ls.add(s.substring(i, i + length));
}
}
}
}
return ls;
} // end of method
}
I wrote this program for school and it almost works, but there is one problem. The goal of the program is to take an inputted string and create a new string out of each word in the input beginning with a vowel.
Example:
input: It is a hot and humid day.
output: Itisaand.
Here is the driver:
public class Driver {
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
System.out.print("Input: ");
String input = console.nextLine();
Class strings = new Class(input);
int beg=0;
for(int j=0;j<input.length();j++)
{
if(strings.isVowel(j)&&(j==0||input.charAt(j-1)==' '))
beg=j;
else if(strings.endWord(j)&&(beg==0||input.charAt(beg-1)==' '))
{
strings.findWord(beg, j);
}
}
System.out.print("Output: ");
strings.printAnswer();
}
}
And here is the class:
public class Class {
String input="",answer="";
public Class(String input1)
{
input = input1;
}
public boolean isVowel(int loc)
{
return (input.charAt(loc)=='U'||input.charAt(loc)=='O'||input.charAt(loc)=='I'||input.charAt(loc)=='E'||input.charAt(loc)=='A'||input.charAt(loc)=='a'||input.charAt(loc)=='e'||input.charAt(loc)=='i'||input.charAt(loc)=='o'||input.charAt(loc)=='u');
}
public boolean endWord(int loc)
{
return (input.charAt(loc)==' '||input.charAt(loc)=='.'||input.charAt(loc)=='?'||input.charAt(loc)=='!');
}
public void findWord(int beg,int end)
{
answer = answer+(input.substring(beg,end));
}
public void printAnswer()
{
System.out.println(answer+".");
}
}
With this code, i get the output:
Itisaa hotandand humidand humid summerand humid summer day.
By removing this piece of code:
&& (j == 0 || input.charAt(j-1) == ' ')
I get the proper output, but it doesn't work if an inputted word has more than one vowel in it.
For example:
input: Apples and bananas.
output: and.
Can someone please explain:
a) why the code is printing out words beginning with consonants as it is and
b) how I could fix it.
Also, the methods in the class I've written can't be changed.
Here's a better algorithm:
split the input into an array of words
iterate over each word
if the word begins with a vowel, append it to the output
The easiest way to split the input would be to use String.split().
Here's a simple implementation:
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
String input = console.nextLine();
String[] words = input.split(" ");
StringBuilder output = new StringBuilder();
for (String s : words) {
if (startsWithVowel(s)) {
output.append(s);
}
else {
output.append(getPunc(s));
}
}
System.out.println(output.toString());
}
public static boolean startsWithVowel(String s) {
char[] vowels = { 'a', 'e', 'i', 'o', 'u' };
char firstChar = s.toLowerCase().charAt(0);
for (char v : vowels) {
if (v == firstChar) {
return true;
}
}
return false;
}
public static String getPunc(String s) {
if (s.matches(".*[.,:;!?]$")) {
int len = s.length();
return s.substring(len - 1, len);
}
return "";
}
The problem with your code was:
It was counting the same word multiple times, due to it finding vowels and starting the word search process over again.
Heres how I went about solving the problem, while still keeping your code looking relatively the same: All I changed was your loop
for(int i=0;i<input.length();i++)
{
if(strings.isVowel(i) &&(i==0 || strings.endWord(i-1))){
beg = i;
for(int j = i; j < input.length();j++) //look for end of word
{
if(strings.endWord(j)) //word has ended
{
i = j; //start from end of last word
strings.findWord(beg, j);
break; //word done, end word search
}
}
}
}
As mentioned above, there are better ways to go about this, and there are some pretty glaring flaws in the setup, but you wanted an answer, so here you go
Normally i would suggest you where to fix your code, but it's seems there is a lot of bad code practice in here.
Mass Concatenation should be apply be StringBuilder.
Never call a class Class
Conditions are too long and can be shorten by a static string of Vowels and apply .contains(Your-Char)
Spaces, Indentations required for readability purposes.
A different way of attacking this problem, may probably accelerate your efficiency.
Another approch will be Split the code by spaces and loop through the resulted array for starting vowels letters and then Append them to the result string.
A better readable and more maintainable version doing what you want:
public static String buildWeirdSentence(String input) {
Pattern vowels = Pattern.compile("A|E|I|O|U|a|e|i|o|u");
Pattern signs = Pattern.compile("!|\\.|,|:|;|\\?");
StringBuilder builder = new StringBuilder();
for (String word : input.split(" ")) {
String firstCharacter = word.substring(0, 1);
Matcher vowelMatcher = vowels.matcher(firstCharacter);
if (vowelMatcher.matches()) {
builder.append(word);
} else {
// we still might want the last character because it might be a sign
int wordLength = word.length();
String lastCharacter = word.substring(wordLength - 1, wordLength);
Matcher signMatcher = signs.matcher(lastCharacter);
if (signMatcher.matches()) {
builder.append(lastCharacter);
}
}
}
return builder.toString();
}
In use:
public static void main(String[] args) {
System.out.println(buildWeirdSentence("It is a hot and humid day.")); // Itisaand.
}
I think best approach is to split input and then check each word if it starts with vowel.
public static void main(String[] args)
{
Scanner console = new Scanner(System.in);
System.out.print("Input: ");
String str = console.next();
String[] input = str.split(" ");
StringBuilder s = new StringBuilder();
String test;
for (int i = 0; i < input.length; i++)
{
test = input[i];
if (test.charAt(0) == 'U' || test.charAt(0) == 'O'
|| test.charAt(0) == 'I' || test.charAt(0) == 'E'
|| test.charAt(0) == 'A' || test.charAt(0) == 'a'
|| test.charAt(0) == 'e' || test.charAt(0) == 'i'
|| test.charAt(0) == 'o' || test.charAt(0) == 'u')
{
s.append(input[i]);
}
}
System.out.println(s);
}
The problem with your code is that you override the first beg when a word has more that vowel. for example with Apples beg goes to 0 and before you could call findWord to catch it, it gets overridden with 4 which is the index of e. And this is what screws up your algorithm.
You need to note that you have already found a vowel until you have called finWord, for that you can add a boolean variable haveFirstVowel and set it the first time you have found one to true and only enter the branch for setting that variable to true if you haven't already set it. After you have called findWord set it back to false.
Next you need to detect the start of a word, otherwise for example the o of hot could wrongly signal a first vowel.
Class strings = new Class(input);
int beg = 0;
boolean haveFirstVowel = false;
for (int j = 0; j < input.length(); j++) {
boolean startOfWord = (beg == 0 || input.charAt(j - 1) == ' ');
if (startOfWord && ! haveFirstVowel && strings.isVowel(j)) {
beg = j;
haveFirstVowel = true;
}
else if (strings.endWord(j) && haveFirstVowel) {
strings.findWord(beg, j);
haveFirstVowel = false;
}
}
System.out.print("Output: ");
strings.printAnswer();
I think overall the algorithm is not bad. It's just that the implementation can definitely be better.
Regarding to the problem, you only need to call findWord() when:
You have found a vowel, and
You have reached the end of a word.
Your code forgot the rule (1), therefore the main() can be modified as followed:
Scanner console = new Scanner(System.in);
System.out.print("Input: ");
String input = console.nextLine();
Class strings = new Class(input);
int beg = 0;
boolean foundVowel = false; // added a flag indicating whether a vowel has been found or not
for (int j = 0; j < input.length(); j++) {
if (strings.isVowel(j) && (j == 0 || input.charAt(j - 1) == ' ')) {
beg = j;
foundVowel = true;
} else if (strings.endWord(j) && (beg == 0 || input.charAt(beg - 1) == ' ')) {
if (foundVowel) { // only call findWord() when you have found a vowel and reached the end of a word
strings.findWord(beg, j);
foundVowel = false; // remember to reset the flag
}
}
}
System.out.print("Output: ");
strings.printAnswer();
I've spend the day working on these two classes. I've come further than I was expecting to yet needless to say I'm running into issues.
Basically I have to take an inputted String and return only the uppercase letters, every second letter, the entire string but with all vowels exchanged with an underscore, number of vowels in the string, and lastly positions of all vowels in the string.
I specifically designed my tester class, I believe correctly, to have a menu to try each command separately so I'm able to test each one.
This is the tester class..
//******************************************
// LetterTest.java
// Written by Sanchez
// 2013
//*******************************************
//===========================================
// This program tests the CharAPI class.
//===========================================
import java.util.Scanner;
public class LetterTest {
public static void main(String[] args){
//create Scanner for user input
Scanner in = new Scanner(System.in);
//get user input
System.out.println("Please enter a string of letters");
String input = in.nextLine();
System.out.println("\nChoose an option: "
+"\n1 - Uppercase, "
+"\n2 - Every Second Letter, "
+"\n3 - Replace vowels "
+"\n4 - Number of vowels "
+"\n5 - Positions of vowels");
int choice = in.nextInt();
//Call the method based on user choice
if (choice == 1) {
//each method returns a String
System.out.println(LetterAPI.bigLetters(input) );
}
else if (choice ==2) {
System.out.println(LetterAPI.secondLetter(input) );
}
else if (choice ==3) {
System.out.println(LetterAPI.vowelsGone(input) );
}
else if (choice ==4) {
System.out.println(LetterAPI.vowelNumber(input) );
}
else {
System.out.println(LetterAPI.vowelPositions(input) );
}
}
}
That seems to be working pretty well and I'm happy with it.
The issue I'm having is in my class with the objects that do the manipulation
I've used the // on a couple things just so I could get it to compile. The 1st, 2nd, and 4th, straight up don't return anything. The third one only exchanges the last letter for an underscore even if it's not a vowel, and the fifth one works pretty well except I'd like to add 1 to all the numbers so the results start at 1 and not 0. I understand that there's a lot going on here but I've spent the day on it and am finally submitting that I am in dire need of help.
This is the code for the objects...
//******************************************
// LetterAPI.java
// Written by Sanchez
// 2013
//*******************************************
//===========================================
// Objects of this class manipulate an inputted string.
//===========================================
import java.util.Scanner;
//contains a set of methods for maniuplaing the string
public class LetterAPI {
//print only uppercase letters
public static String bigLetters(String input) {
String result = "";
for (int i = 0; i <input.length(); i++) {
char currentLetter=input.charAt(i);
if (Character.isUpperCase(currentLetter))
result = result;
}
return result;
}
//print every second letter
public static String secondLetter(String input) {
String result = "";
for (int i = 0; i <input.length(); i++) {
//result = input.charAt(input);
}
return result;
}
//all vowels replaced by underscores
public static String vowelsGone(String input) {
String result ="aeiouAEIOU";
for (int i = 0; i<result.length();i++) {
result=input.replace(result.charAt(i), '_');
}
return result;
}
//the numbers of vowels
public static String vowelNumber(String input) {
String result = "";
for (int i = 0; i <input.length(); i++) {
if (Character.toLowerCase(input.charAt(i)) == 'a' || Character.toLowerCase(input.charAt(i)) == 'e' || Character.toLowerCase(input.charAt(i)) == 'i' || Character.toLowerCase(input.charAt(i)) == 'o' || Character.toLowerCase(input.charAt(i)) == 'u') {
i++;
}
}
return result;
}
//the positions of all vowels
public static String vowelPositions(String input) {
String result = "";
for (int i = 0; i <input.length(); i++) {
if (Character.toLowerCase(input.charAt(i)) == 'a' || Character.toLowerCase(input.charAt(i)) == 'e' || Character.toLowerCase(input.charAt(i)) == 'i' || Character.toLowerCase(input.charAt(i)) == 'o' || Character.toLowerCase(input.charAt(i)) == 'u') {
result = result + i + " ";
}
}
return result;
}
}
===UPDATE===
Thank you everyone! I've made some progress thank god. I've gotten the 3rd and 4th to work great. The first one was giving only the last uppercase but now is repeating my input. The second one is just giving me back the 1st letter. As for the last one I tried parenthesis but I seemed to have broke it so I put it back for now. That's not as critical..at least it works! If I can't figure that out I'll have to put a note that the count starts at 0. But the first two are killing me..at least it compiles. Here's where I'm at so far...
//******************************************
// LetterAPI.java
// Written by Sanchez
// 2013
//*******************************************
//===========================================
// Objects of this class manipulate an inputted string.
//===========================================
import java.util.Scanner;
//contains a set of methods for maniuplaing the string
public class LetterAPI {
//print only uppercase letters
public static String bigLetters(String input) {
String result = "";
char cl;
for (int i = 0; i <input.length(); i++) {
cl=input.charAt(i);
if (Character.isUpperCase(cl))
input = input + cl;
}
return input;
}
//print every second letter
public static String secondLetter(String input) {
String result = "";
for (int i=0; i<input.length(); i+=2) {
input = input + input.charAt(i) + " ";
}
return input;
}
//all vowels replaced by underscores
public static String vowelsGone(String input) {
String vowels ="aeiouAEIOU";
for (int i = 0; i<vowels.length();i++) {
input=input.replace(vowels.charAt(i), '_');
}
return input;
}
//the numbers of vowels
public static String vowelNumber(String input) {
String result = "";
int count = 0;
for (int i = 0; i <input.length(); i++) {
if (Character.toLowerCase(input.charAt(i)) == 'a' || Character.toLowerCase(input.charAt(i)) == 'e' || Character.toLowerCase( input.charAt(i)) == 'i' || Character.toLowerCase(input.charAt(i)) == 'o' || Character.toLowerCase(input.charAt(i)) == 'u') {
count++;
result = count + " ";
}
}
return result;
}
//the positions of all vowels
public static String vowelPositions(String input) {
String result = "";
for (int i = 0; i <input.length(); i++) {
if (Character.toLowerCase(input.charAt(i)) == 'a' || Character.toLowerCase(input.charAt(i)) == 'e' || Character.toLowerCase(input.charAt(i)) == 'i' || Character.toLowerCase(input.charAt(i)) == 'o' || Character.toLowerCase(input.charAt(i)) == 'u') {
result = result + i + " ";
}
}
return result;
}
}
Hints:
In part 1, you do this: result = result; That is nonsensical. It does nothing.
In part 2, the compilation error is because you are trying to assign a char to a String. That's not legal. But it is also not what you should be trying to do. (Think "append", not "assign" ...)
In part 3, the first mistake is this: String result = "aeiouAEIOU";. In fact, it should be String result = input;.
In part 4, you are counting all vowels, not each different vowel. You also need to turn the count (or counts) into a String (in result).
About part 5 you say: "works pretty well except I'd like to add 1 to all the numbers". So do it!