I am currently in an Intro to Programming class at San Jose and as part of our assignment we were to create a class with methods that either return a string with the first letters of each word or the last letters of each word.
The instance variable "phrase" holds the phrase that is accessed in the methods.
Here are the rules:
The words are separated by spaces,
It starts with a letter,
It does not end with a space,
There are never 2 consecutive spaces,
There are never 2 consecutive digits or punctuation.
Both the firstLetter() and lastLetter() methods must return an empty string if the phrase is empty.
My question is: What is a more efficient solution to this problem? I am new to algorithms so I would appreciate a more seasoned approach to this simple problem. In the firstLetter() and the lastLetter() method, would I check the status of two characters at a time within the for loop or just one?
Here is my code:
/**
* Processes first and last letters of words
* #author (Adrian DeRose)
*/
public class StartToFinish
{
private String phrase;
/**
* Constructs a StartToFinish object
* #param myString the phase for this object
*/
public StartToFinish(String myString)
{
this.phrase = myString;
}
/**
* Gets first letter of every word in string.
*
* #return first letter of every word in string
*/
public String firstLetters()
{
String firstLetters = "";
if (Character.isLetter(this.phrase.charAt(0)))
{
firstLetters += this.phrase.substring(0,1);
}
for (int i = 1; i < this.phrase.length(); i++)
{
char currentCharacter = this.phrase.charAt(i);
String previousCharacter = Character.toString(this.phrase.charAt(i-1));
if (Character.isLetter(currentCharacter) && previousCharacter.equals(" "))
{
String characterString = Character.toString(currentCharacter);
firstLetters += characterString;
}
}
return firstLetters;
}
/**
* Gets last letter of every word in string.
*
* #return last letter of every word in string
*/
public String lastLetters()
{
String lastLetters = "";
char lastCharacter = this.phrase.charAt(lastIndex);
if (this.phrase.length() == 0)
{
return "";
}
for (int i = 1; i < this.phrase.length(); i++)
{
char currentCharacter = this.phrase.charAt(i);
char previousCharacter = this.phrase.charAt(i-1);
if (Character.isLetter(previousCharacter) && !Character.isLetter(currentCharacter))
{
String previousCharacterString = Character.toString(previousCharacter);
lastLetters += previousCharacterString;
}
}
if (Character.isLetter(lastCharacter))
{
lastLetters += Character.toString(lastCharacter);
}
return lastLetters;
}
}
Thank you!
i don't know if this is what you are looking for, but this is much more simple way to write the same (sorry for my English)
String a="john snow winter is comming";
String[] parts = a.split(" ");
for(String word:parts){
System.out.println("first letter "+word.charAt(0)+ " last letter "+word.charAt(word.length()-1));
}
I don't think so you have to write all those code just use java function:
String a = "Hello";
System.out.println("First:"+a.charAt(0));
System.out.println("Last:"+a.charAt(a.length()-1));
Output:
First:H
Last:o
One of the solution I will provide is :
1. Check if the phrase is empty in the constructor.
2. Begin with a split, and then do some check.
In the constructor (This isn't needed in your case btw)
splitedPhrase = phrase.split(' ');
In the dedicated function
public String firstLetters() {
String result = "";
for(String word : splitedPhrase) {
if (Character.isLetter(word.charAt(0)))
result+=word.charAt(0);
}
return result;
}
And you just have to change the charAt for the LastLetter function, like
word.charAt(word.length-1)
Hope this help, despite some people already posted, I think this will better do what your algortihm need.
If I understand your question correctly, I think this is what you're looking for:-
public class StartToFinish {
private String phrase;
private String[] words;
private String firstLetters = "";
private String lastLetters = "";
/**
* Constructs a StartToFinish object
*
* #param myString
* the phase for this object
*/
public StartToFinish(String myString) {
this.phrase = myString;
words = phrase.split(" ");
for (String string : words) {
if (string.length() == 0)
continue;
if (Character.isLetter(string.charAt(0))) {
firstLetters += string.charAt(0);
}
if (Character.isLetter(string.charAt(string.length() - 1))) {
lastLetters += string.charAt(string.length() - 1);
}
}
}
/**
* Gets first letter of every word in string.
*
* #return first letter of every word in string
*/
public String firstLetters() {
return firstLetters;
}
/**
* Gets last letter of every word in string.
*
* #return last letter of every word in string
*/
public String lastLetters() {
return lastLetters;
}
}
Related
/* Programs goal is to take two strings and use a method to alternate the characters.
example - "test" "case" -> "tceasste"
Sorry I tried looking at other similar questions but I didn't understand how they worked as I am very new to Java and coding in general.
*/
public class MyProgram extends ConsoleProgram
{
public void run()
{
System.out.println(sCombine("test","case")); //"tceasste"
System.out.println(sCombine("avalanche","dog")); //"advoaglanche"
System.out.println(sCombine("","water")); //"water"
}
public String sCombine(String a, String b)
{
String result = "";
int lengtha = a.length();
int lengthb = b.length();
int lengthc = 0;
if(lengtha < lengthb)
{
lengthc = lengtha;
}
else
{
lengthc = lengthb;
}
for(int i = 0; i < lengthc; i++)
{
char currentA = a.charAt(i);
char currentB = b.charAt(i);
result += a;
result += b;
}
return result;
}
}
The problem is that you're doing:
result += a;
You need to do:
result += currentA;
I would also suggest looking at the StringBuilder class. It has a lot of built in functionality for things of this nature :)
Just another way. Read all the comments in code:
/**
* Sequentially blends two strings together one character at a time, for
* example, if the first argument was "cat" and the second argument was
* "dog" then the returned result will be: "cdaotg".<br><br>
*
* <b>Example Usage:</b><pre>
* {#code
* final String a = "cat";
* final String b = "elephant";
* String newString = sCombine(a, b);
* System.out.println(newString);
* // Console will display: cealte }
*
* OR
* {#code
* final String a = "cat";
* final String b = "elephant";
* String newString = sCombine(a, b, true); // true is optionally supplied here.
* System.out.println(newString);
* // Console will display: eclaetphant }</pre>
*
* #param stringA (String) The first String to blend.<br>
*
* #param stringB (String) The second String to blend.<br>
*
* #param startWithLongest (Optional - boolean varArgs) Default is false <pre>
* whereas this method will always take the first
* supplied argument and blend the second argument
* into it. In this default situation, the first
* argument is always considered to contain the
* longest String. If however, the second argument
* contains more characters then the those extra
* characters will be truncated, for example: "cat"
* and "elephant". Result will be: "cealte". It would
* be beneficial to always pass the longest string as
* the first argument in order to achieve the result
* of: "eclaetphant".
*
* If boolean true is supplied to this optional parameter
* then the longest argument passed to this method will
* always be considered as the first argument rather than
* the first supplied argument, for example: "cat" as the
* first argument and "elephant" as the second argument
* and true as the third argument will return a result
* of "eclaetphant".
*
* Supplying nothing forces default to be used.</pre>
*
* #return (String) The blended String;
*/
public static String sCombine(final String stringA, final String stringB,
final boolean... startWithLongest) {
String strgA = stringA, strgB = stringB; // So to maintain original Strings
/* If `true` is supplied to the startWithLongest optional
vararg parameter then ensure the String argument with the
most characters is the first argument (if true, always place
the longest first). */
if (startWithLongest.length > 0 && startWithLongest[0]) {
if (strgB.length() > strgA.length()) {
strgA = stringB;
strgB = stringA;
}
}
// Build the new blended string
StringBuilder sb = new StringBuilder("");
for (int i = 0; i < strgA.length(); i++) {
sb.append(strgA.charAt(i))
/* 'Ternary Operator' is used here to ensure strgB
contains the current index to carry on. If not
then just the remaining characters of strgA are
sequentially apended to the StringBuilder object
to finish up things. */
.append(i < strgB.length() ? strgB.charAt(i) : "");
}
return sb.toString();
}
You can use a loop that iterates the maximum length of both the strings. Then you can extract the individual character at the ith position and add it alternatively to a resulting String object. I have used StringBuiler as it mutable( diff here ) This is the code that I have attached.
public class MyProgram {
public static void main(String[] args) {
System.out.println(sCombine("test", "case")); // "tceasste"
System.out.println(sCombine("avalanche", "dog")); // "advoaglanche"
System.out.println(sCombine("", "water")); // "water"
}
public static String sCombine(String a, String b) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < Math.max(a.length(), b.length()); i++) {
char aChar = i < a.length() ? a.charAt(i) : '#';
char bChar = i < b.length() ? b.charAt(i) : '#';
if (aChar != '#') {
result.append(aChar + "");
}
if (bChar != '#') {
result.append(bChar + "");
}
}
return result.toString();
}
}
and the output is :
tceasste
advoaglanche
water
You can use substring to savely append the remainder of the Strings. Should the limit be out of bounds, no exception will be thrown, because substring will just return an empty String.
public String sCombine(String a, String b) {
final StringBuilder builder = new StringBuilder();
final int min = Math.min(a.length(), b.length());
for (int i = 0; i < min; i++) {
builder.append(a.charAt(i)).append(b.charAt(i));
}
builder.append(a.substring(min)).append(b.substring(min));
return builder.toString();
}
take two strings and use a method to alternate the characters.
example - "test" "case" -> "tceasste"
private static String mixedUp(String first, String second)
{
First, identify the shorter string so it won't attempt to pull a character that is out out bounds
int length = (first.length() > second.length())
? second.length() : first.length();
Then for that length, add their alternating characters to a new String() Object like so:
String output = new String();
for(int index = 0; index < length; index++)
{
output += first.charAt(index);
output += second.charAt(index);
}
You can use substring to savely append the remainder of the Strings. Should the limit be out of bounds, no exception will be thrown, because substring will just return an empty String. - #thinkgruen
You can add the rest of the characters using the ternary operator again like so:
output += (first.length() > second.length())
? second.substring(length) : first.substring(length);
return output;
}
I'm coding in the Java programming language.
The purpose of this code is to go through a set and return an array of all sets of words containing double letters (there should be one for each letter of the alphabet).
This is the code I have so far, right now it's returning the number 23 when it should be returning 26 (again, for each letter of the alphabet). Any guidance on what I'm doing wrong would be so so helpful!
/**
* Returns an array of all sets of words containing double letters,
* one set for each letter of the alphabet. There should be a set
* for all words containing "aa", one for "bb", etc.
* #param words set of words
* #return array of sets, one for each doubled letter in the alphabet
*/
public Set<String>[] allWordSetsContainingDoubleLetters(Set<String> words)
{
Set<String> sets[] = new HashSet[26];
int count = 0;
for (String word : words)
{
String lowerCase = word.toLowerCase();
for (int i = 0; i <= sets.length; i++)
{
char c = (char) ('a' + i);
String str = "" + c + c;
if (lowerCase.contains(str))
{
if (sets[i] == null)
{
sets[i] = new HashSet<String>();
count++;
}
sets[i].add(word);
}
}
}
Set<String> result[] = new HashSet[count];
count = 0;
for (Set<String> s : sets)
{
if (s != null)
{
result[count++] = s;
}
}
return result;
}
Currently, I am able to translate an English word to pig latin. My lab assignment says that punctuation occurring before the word should be removed, stored, and prepended to the piglatinized word. Punctuation occurring after the word should be removed, stored, and appended to the piglatinized word. Any punctuation that is in the middle of the word is to be treated as a regular letter.
For example:
what? -> atwhay?
Oh!!! -> Ohway!!!
"hello" -> "ellohay"
don't -> on'tday
"pell-mell" -> "ell-mellpayā€¯
This is what I have right now to find and store the punctuations:
public static final String punct = ",./;:'\"?<>[]{}|`~!##$%^&*()";
String startPunct = "";
String endPunct = "";
for (int c = 0; c < s.length(); c++) {
for (int i = 0; i < punct.length(); i++) {
if (s.charAt(c) == punct.charAt(i)) {
startPunct = startPunct + s.charAt(c);
}
}
}
If needed, this is the basic idea of how I print my translated word:
s = s.substring(i) + s.substring(0, i) + "ay";
return s;
So the question is, how do I preserve the punctuation so that it appears in the beginning and at the end of the translated word (recursion preferably but regex is fine)?
Any help is much appreciated. Thanks in advance.
Some problems lend themselves to recursion but your task is not one of them, in my opinion. Hence the below code uses regular expressions.
Notes after the code.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Converts an English word into pig latin. Algorithm follows.
* <ol>
* <li>All initial consonants are moved to the end of the word and <i>ay</i> is appended, for
* example <i>what</i> becomes <i>atwhay</i></li>
* <li>For words that begin with a vowel, <i>way</i> is appended to the word for example <i>oh</i>
* becomes <i>ohway</i>.</li>
* </ol>
* Additional stipulations include the following.
* <ol>
* <li>Initial punctuation and terminal punctuation are unchanged in the converted word, for
* example if the original word ends with a question mark then the converted word also ends with a
* question mark meaning that <i>what?</i> becomes <i>atwhay?</i></li>
* <li>Case sensitivity is preserved.</li>
* </ol>
*/
public class PigLatin {
private static final String VOWELS = "aeiou";
private static int getIndexOfFirstVowelInWord(String word) {
int index = -1;
if (word != null && !word.isBlank()) {
word = word.strip();
word = word.toLowerCase();
char[] letters = word.toCharArray();
for (int i = 0; i < letters.length; i++) {
if (VOWELS.indexOf(letters[i]) >= 0) {
index = i;
break;
}
}
}
return index;
}
/**
* First method invoked when this class launched via <tt>java</tt> command. Recognizes a single
* command argument which is the word to be converted into pig latin.
*
* #param args - <tt>java</tt> command arguments.
*/
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("ARGS: word");
}
else {
System.out.printf("Word: ^%s^%n", args[0]);
Pattern pattern = Pattern.compile("^([!?\"'():;,.-]*)(\\w+[!?\"'():;,.-]*\\w+)([!?\"'():;,.-]*)$");
Matcher matcher = pattern.matcher(args[0]);
if (matcher.matches()) {
String initial = matcher.group(1);
String word = matcher.group(2);
word = word.strip();
String terminal = matcher.group(3);
int index = getIndexOfFirstVowelInWord(word);
if (index == 0) {
word += "way";
}
else {
String suffix = word.substring(0, index);
word = word.substring(index);
word += suffix;
word += "ay";
}
String result = initial + word + terminal;
System.out.println("Result: " + result);
}
else {
System.out.println("No match.");
}
}
}
}
I test for punctuation which is commonly found in prose, including the following.
exclamation mark
question mark
double quote
single quote
parentheses
colon
semi colon
comma
period
dash
The regular expression contains three groups.
First group is leading punctuation.
Second group is actual word, which may contain embedded punctuation.
Third group is trailing punctuation.
We only need to handle the second group. The handling algorithm is described in the class comments in the above code.
I tested the code for all the example words in your question and got your expected result for each word.
Trying to create a method findNewLineWithChar() which returns a String and accepts a Scanner scn and a char c. It returns the line of the scanner which contains c.
I've tried using a string to store the value of currentLine, but it seemed to convolute my code and not provide any answers anyways. I would love to use a String[], but I get a NullPointerException. What am I exactly doing wrong?
public static String findLineWithChar(Scanner scn, char c) {
/*
* findLineWithChar returns line in scanner if line has char c
* #param scanner
* #param c
*/
String result = "";
String[] stringArray = new String[10]; //accepts max 10 lines
int counter = 0; //populate string array from scn
while(scn.hasNextLine()) {
stringArray[counter] = scn.nextLine();
counter++;
}
//iterate through each element in string array
for (int i = 0; i < 10; i++) {
if (stringArray[i].contains(c + "")) {
result = stringArray[i];
System.out.println(stringArray[i]);
break;
} else {
result = "";
}
}
return result;
}
It works if I feed it a true statement,
findLineWithChar(new Scanner("Look here!\nLook there!\nExtra extra!"), 'x') returns Extra extra!, but findLineWithChar(new Scanner("Look here!\nLook there!\nExtra extra!"), 'q') returns a NullPointerException. How do I deal with this?
First, Javadoc comments go before the method (and start with /**). Second, you don't need an array here; just keep a count to make sure you don't consume more than ten lines (assuming that's necessary). Instead of setting a return variable and breaking the loop, I would return when a matching line is found. I would also prefer String.indexOf(int) to building one character String(s) for comparison. And, add a default return value for when nothing matches. Like,
/**
* findLineWithChar returns line in scanner if line has char c
*
* #param scanner
*
* #param c
*/
public static String findLineWithChar(Scanner scn, char c) {
int counter = 0;
while (scn.hasNextLine() && counter < 10) {
String line = scn.nextLine();
if (line.indexOf(c) > -1) {
return line;
}
counter++;
}
return "";
}
You almost got it! Just change condition of your while loop.
from this:
while(scn.hasNextLine()) {
to this:
while(scn.hasNextLine() && counter < 10) {
I have been tasked to create a String method that will take any input with varying lengths and random capitalization and return a string that has the first letter as uppercase, and the rest as lower case.
Since the program we are building is solitaire, this method should return inputs such as "aarts," "HEARTS," "heartss," etc as "Hearts" and this would be the same for the other three suits.
I have figured out how to correct inputs that are randomly capitalized, but not for ones that are varying lengths or have typos. The code below is where I am trying to alter inputs.
/**
* Converts the given string to title case, where the first
* letter is capitalized and the rest of the string is in
* lower case.
*
* #param s a string with unknown capitalization
* #return a title-case version of the string
*/
public static String toTitleCase(String s)
{
String result = "";
result = s.substring(0,1).toUpperCase() + s.substring(1).toLowerCase();
return result;
}
The next code is the code that I am using to test the code above.
private void main()
{
testToTitleCase("HEARTS", "Hearts");
testToTitleCase("hEarts", "Hearts");
testToTitleCase("HEART", "Hearts");
testToTitleCase("hEaRtS", "Hearts");
testToTitleCase("heartss", "Hearts");
}
private void testToTitleCase( String input, String expectedOutput)
{
String actualOutput = Card.toTitleCase(input);
System.out.println("Testing whether toTitleCase('" + input +
"') returns '" + expectedOutput + "'.");
if (expectedOutput.equals(actualOutput))
{
System.out.println("Success!");
}
else
{
System.out.println("Failure! The actual output was '"
+ actualOutput + "'");
}
}
To correct typos, you can match the discrete characters of a string with original string and count the number of matches and implement accordingly. For example:
public static String verifyInput(String typo) {
String correctString[] = { "Spades", "Hearts", "Ace", "Club" };
// A number to store maximum matches
int maxMatch = 0;
// Final String
String finalStr = "";
// Iterate through array to find best match
for (String corrStr : correctString) {
int match = 0;
String dis = "";
// Form discrete string
// We match only discrete characters
for (char x : typo.toCharArray())
if (corrStr.toLowerCase().contains(String.valueOf(x).toLowerCase())
&& !dis.contains(String.valueOf(x))) {
dis += x;
match++;
}
// Special stuff for ace
if (corrStr.equals("Ace") && match > corrStr.length() / 2 && typo.length() == 3)
return corrStr;
// If the current string had more matches than previous, replace
// previous with current
if (match > maxMatch) {
maxMatch = match;
finalStr = corrStr;
}
}
return finalStr;
}
Input: heartss, aarts, HEARTS, aaarhzzzzs, farts, husthusahuiu
Output: Hearts
Input: spSUgyDz
Output: Spades
Input: ACD
Output: Ace
Calculate the Levenshtein distance between the input string and each of the possible legal values ("hearts", "clubs", "diamonds", "spades"). The incredibly useful Apache commons-lang library includes a function for that. The pair with the lowest distance is probably the right one - but make sure you set an upper threshold on the distance; if the user enters "sushi on rye with mustard" then one of the values will be a closer match than the others, but that won't mean it's the correct match.