Better way to invert cases of characters in a string in Java - java

As a novice Java programmer who barely got started in Java programming, I am totally exhausted in trying to find a solution to this issue. A course that I am currently studying gave homework that asked me to create a Java class that has a sort of “reverse” method that returns a new version of the string
of the current string where the capitalization is reversed (i.e., lowercase to uppercase
and uppercase to lowercase) for the alphabetical characters specified in a given condition. Say if I were to reverse “abc, XYZ; 123.” using reverse("bcdxyz#3210."), it must return "aBC, xyz; 123.". (P.S: the class ignores numbers and special characters and the variable "myString" is where the "abc, XYZ; 123." goes to.). So far, I've only managed to return out "aBC, XYZ; 123." with the code below. Am I missing something here?
public String reverse(String arg) {
// TODO Implement method
String arg_no_sym = arg.replaceAll("[^a-zA-Z0-9]","");
String arg_perfect = arg_no_sym.replaceAll("\\d","");
if (myString != null) {
char[] arrayOfReplaceChars = arg_perfect.toCharArray();
char[] arrayOfmyString = myString.toCharArray();
for (int i = 0; i < arg_perfect.length(); i++) {
myString = myString.replace(String.valueOf((arrayOfReplaceChars[i])), String.valueOf((arrayOfReplaceChars[i])).toUpperCase());
}
return myString;
}
else {
return "";
}
}

How about using the methods isUpperCase() and isLowerCase() to check the case of the letters and then use toUpperCase() and toLowerCase() to change the case of them?

Related

java startsWith() method with custom rules

I implement typing trainer and would like to create my special String startsWith() method with specific rules.
For example: '-' char should be equal to any long hyphen ('‒', etc). Also I'll add other rules for special accent characters (e equals é, but not é equals e).
public class TestCustomStartsWith {
private static Map<Character, List<Character>> identityMap = new HashMap<>();
static { // different hyphens: ‒, –, —, ―
List<Character> list = new LinkedList<>();
list.add('‒');
list.add('–'); // etc
identityMap.put('-', list);
}
public static void main(String[] args) {
System.out.println(startsWith("‒d--", "-"));
}
public static boolean startsWith(String s, String prefix) {
if (s.startsWith(prefix)) return true;
if (prefix.length() > s.length()) return false;
int i = prefix.length();
while (--i >= 0) {
if (prefix.charAt(i) != s.charAt(i)) {
List<Character> list = identityMap.get(prefix.charAt(i));
if ((list == null) || (!list.contains(s.charAt(i)))) return false;
}
}
return true;
}
}
I could just replace all kinds of long hyphens with '-' char, but if there will be more rules, I'm afraid replacing will be too slow.
How can I improve this algorithm?
I don't know all of your custom rules, but would a regular expression work?
The user is passing in a String. Create a method to convert that String to a regex, e.g.
replace a short hyphen with short or long ([-‒]),
same for your accents, e becomes [eé]
Prepend with the start of word dohicky (\b),
Then convert this to a regex and give it a go.
Note that the list of replacements could be kept in a Map as suggested by Tobbias. Your code could be something like
public boolean myStartsWith(String testString, String startsWith) {
for (Map.Entry<String,String> me : fancyTransformMap) {
startsWith = startsWith.replaceAll(me.getKey(), me.getValue());
}
return testString.matches('\b' + startsWith);
}
p.s. I'm not a regex super-guru so if there may be possible improvements.
I'd think something like a HashMap that maps the undesirable characters to what you want them to be interpreted as might be the way to go if you are worried about performance;
HashMap<Character, Character> fastMap = new Map<Character, Character>();
// read it as '<long hyphen> can be interpreted as <regular-hyphen>
fastMap.add('–', '-');
fastMap.add('é', 'e');
fastMap.add('è', 'e');
fastMap.add('?', '?');
...
// and so on
That way you could ask for the value of the key: value = map.get(key).
However, this will only work as long as you have unique key-values. The caveat is that é can't be interpreted as è with this method - all the keys must be unique. However, if you are worried about performance, this is an exceedingly fast way of doing it, since the lookup time for a HashMap is pretty close to being O(1). But as others on this page has written, premature optimization is often a bad idea - try implementing something that works first, and if at the end of it you find it is too slow, then optimize.

Regular Expressions in Java - Checking instance variables start with a capital letter?

How am I able to check if both the countryName and capitalName instance variables start with a capital letter? I'm sure I have to use regular expressions involving somthing like this "^[A-Z]" but am not sure how or where to put the full code.
I am a beginner at java and would appreciate any help or suggestions.
java.util.regex.*;
public class CountryInfo {
private String countryName;
private String capitalName;
public CountryInfo (String countryName, String capitalName) {
super();
this.countryName=countryName;
this.capitalName=capitalName;
}
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
public String getCapitalName() {
return capitalName;
}
public void setCapitalName(String capitalName) {
this.capitalName = capitalName;
}
}
The easiest way is to use the following code
char c = countryName.charAt(0);
if (c >= 'A' && c <= 'Z')
//first character is capital letter!
Withouth using regex, which may be complex for a beginner.
Where to put the code?
Probably in the constructor to check if it's capital letter or not, but you should explain what you need to do if it's a capital letter and what if it isn't to be sure where to put it.
Use this pattern to check:
\b[A-Z]
I don't know what exactly your function is supposed to do when it gets a match, so I can't really tell you where to put it. The most sensible place would probably in the constructor.
Regex based solution as you desired using String#matches(String regex)
Create a new method in the same class as:
public boolean isValidDate() {
boolean valid = true;
if (!this.capitalName.matches("^[A-Z].*$"))
valid = false;
else if (!this.countryName.matches("^[A-Z].*$"))
valid = false;
return valid;
}
Now after creating an instance and populating your object you can call: isValidDate() to know whether data is valid or not.

Ordering a string alphabetically - did I miss something obvious?

public class Anagram {
public static void main(String[] args) {
String a = "Despera tion-".toLowerCase();
String b = "A Rope Ends It".toLowerCase();
String aSorted = sortStringAlphabetically(a);
String bSorted = sortStringAlphabetically(b);
if(aSorted.equals(bSorted)){
System.out.println("Anagram Found!");
}else{
System.out.println("No anagram was found");
}
}
public static String sortStringAlphabetically(String s) {
char[] ca = s.toCharArray();
int cnt = 0;
ArrayList al = new ArrayList();
for (int i = 0; i < ca.length; i++) {
if (Character.isLetter(ca[cnt]))
al.add(ca[cnt]);
cnt++;
}
Collections.sort(al);
return al.toString();
}
}
As a learner, I hacked up this boolean Anagram checker. My chosen solution was to create a sortStringAlphabetically method seems to do just too much type-juggling String -> chars[] -> ArrayList ->String - given that I do just want to compare 2 strings to test whether one phrase is an anagram of another - could I have done it with less type-juggling?
ps The tutors solution was a mile away from my attempt, and probably much better for a lot of reasons - but I am really trying to get a handle on all the different Collection types.
http://www.home.hs-karlsruhe.de/~pach0003/informatik_1/aufgaben/en/doc/src-html/de/hska/java/exercises/arrays/Anagram.html#line.18
EDIT
FTW here is the original challenge, I realise I wandered away from the solution.
http://www.home.hs-karlsruhe.de/~pach0003/informatik_1/aufgaben/en/arrays.html
My initial kneejerk reaction was to simply work though array a, knocking out those chars which matched with array b - but that seemingly required me to rebuild the array at every iteration - Many thanks for all your efforts to educate me.
There are different ways to improve this, if you go with this algorithm.
First, you don't necessarily need to create a character array. You can use String.charAt() to access a specific character of your string.
Second, you don't need a list. If you used a SortedMultiSet or a SortedBag, you could just add things in sorted order. If you write a function that creates the SortedMultiSet from your string, you could just compare the sets without rebuilding the string.
Note: I don't know what libraries you're allowed to use (Google and Apache have these types), but you can always 'brew your own'.
Also, make sure to use generics for your types. Just defining ArrayLists is pretty risky, IMHO.
You could just sort the string without using a list:
public static String sortStringAlphabetically(String s) {
String lettersOnly = s.replaceAll("\\W", "");
char[] chars = lettersOnly.toCharArray();
Arrays.sort(chars);
return new String(chars);
}
N.B. I haven't actually tried running the code.
Your algorithm, but shorter (and yet, slower). The "type-juggling" is done "implicitly" in Java's various library classes:
public static boolean isAnagram(String a, String b) {
List<String> listA = new ArrayList<String>(Arrays.asList(
a.toLowerCase().replaceAll("\\W", "").split("")));
List<String> listB = new ArrayList<String>(Arrays.asList(
b.toLowerCase().replaceAll("\\W", "").split("")));
Collections.sort(listA);
Collections.sort(listB);
return listA.equals(listB);
}
Optionally, replace the \W regular expression to exclude those letters that you don't want to consider for the anagram
public class Anagram {
public static void main(String[] args) throws Exception {
String s1 = "Despera tion-";
String s2 = "A Rope Ends It";
anagramCheck(s1, s2);
}
private static void anagramCheck(String s1, String s2) {
if (isAnagram(s1, s2)) {
System.out.println("Anagram Found!");
} else {
System.out.println("No anagram was found");
}
}
private static boolean isAnagram(String s1, String s2) {
return sort(s1).equals(sort(s2));
}
private static String sort(String s) {
char[] array = s.replaceAll("\\W", "").toLowerCase().toCharArray();
Arrays.sort(array);
return new String(array);
}
}

Why isnt this returning the new string?

I have a recursive method that reversed a string (HW assignment, has to be recursive). I did it....but its only returning the value of the string after the first pass. By analyzing the output after each pass i can see it does do its job correctly. heres my code, and the output i get below it:
String s = "Hello, I love you wont you tell me your name?";
int k=0;
public String reverseThisString(String s) {
if(k!=s.length()) {
String first =s.substring(0,k)+s.charAt(s.length()-1);
String end = ""+s.substring(k, s.length()-1);
k++;
s=first+end;
System.out.println(s);
this.reverseThisString(s);
}
return s;
}
output:
?Hello, I love you wont you tell me your name
I think you need to change this:
this.reverseThisString(s);
to this:
return this.reverseThisString(s);
otherwise the result of the method call is simply discarded.
I would also recommed that you change k to be a parameter to the method rather than a member.
Like Mark said, you forgot the return statement.
Also, there is an easier way to reverse a string (which is my current homework too :P )
public String reverse(String s) {
if(s.length() <= 1)
return s;
return reverse(s.substring(1))+s.charAt(0);
}

Front-popping a Java String

Having read the documentation of Java's String class, it doesn't appear to support popping from front(which does make sense since it's basically a char array). Is there an easy way to do something like
String firstLetter = someString.popFront();
which would remove the first character from the string and return it?
A String in Java is immutable, so you can't "remove" characters from it.
You can use substring to get parts of the String.
String firstLetter = someString.substring(0, 1);
someString = someString.substring(1);
You can easily implement this by using java.lang.StringBuilder's charAt() and deleteCharAt() methods. StringBuilder also implements a toString() method.
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/StringBuilder.html
I don't think there is something like that (even because strings can't be changed - a new one needs to be created), but You can use charAt and subString to implement your own.
An example of charAt:
String aString = "is this your homework Larry?";
char aChar = aString.charAt(0);
Then subString:
String anotherString = aString.substring(1, aString.length());
So you basically want to have the String in a FIFO stack? For that you can use a LinkedList which offers under each a pop() method to pop the first from the stack.
To get all characters of a String in a LinkedList, do so:
String string = "Hello World";
LinkedList<Character> chars = new LinkedList<Character>();
for (int i = 0; i < string.length(); i++) chars.add(string.charAt(i));
Then you can pop it as follows:
char c = chars.pop();
// ...
Update: I didn't see the comment that you'd like to be able to get the remaining characters back as a string. Well, your best bet is to create and implement your own StringStack or so. Here's a kickoff example:
public class StringStack {
private String string;
private int i;
public StringStack(String string) {
this.string = string;
}
public char pop() {
if (i >= string.length()) throw new IllegalStateException("Stack is empty");
return string.charAt(i++);
}
public String toString() {
if (i >= string.length()) throw new IllegalStateException("Stack is empty");
return string.substring(i, string.length());
}
}
You can use it as follows:
String string = "Hello World";
StringStack stack = new StringStack(string);
char c = stack.pop();
String remnant = stack.toString();
// ...
To make it more solid, you can eventually compose a LinkedList.
You should look at a StringReader. The read() method returns a single character.

Categories

Resources