Delete last occurrence in string - java

I am trying to trim a string to the first occurrence of a specific word in a single string of comma separated words. E.g.:
deleteLastOccurrence("foo,bar,dog,cat,dog,bird","dog")
should return
"foo,bar,dog"
I have the following, and it doesn't seem to be working correctly:
public String deleteLastOccurrence(String original, String target){
String[] arr = original.split(",");
arr = Arrays.copyOfRange(arr, Arrays.asList(arr).indexOf(target), original.length()-1);
path = StringUtils.join(pathArray,",");
}
Any suggestions on a simpler method? Thanks in advance...

Use regex replace:
public static String deleteLastOccurrence(String original, String target){
return original.replaceAll("(,)?\\b" + target + "\\b.*", "$1" + target);
}
This code also works when the target is the first or last word in the original (hence the regex syntax \b which means "word boundary")
Also, rename your method to deleteAfterFirstOccurrence(), because your current name is misleading: The "last occurrence" is irrelevant to what you want.
Here's a little test:
public static void main(String[] args) {
// Test for target in middle:
System.out.println(deleteLastOccurrence("foo,bar,dog,cat,dog,bird,dog", "dog"));
// Test for target at start:
System.out.println(deleteLastOccurrence("dog,bar,dog,cat,dog,bird,dog", "dog"));
// Test for target at end:
System.out.println(deleteLastOccurrence("foo,bar,cat,bird,dog", "dog"));
}
Output:
foo,bar,dog
dog
foo,bar,cat,bird,dog

UPDATE: Looked closer at question and realized that I wrote the name of the method, not the result OP wanted. So, it just gets rid of the last occurrence, doesn't trim after it. Oh well! :)
Depending on your style, you might not think this is simpler. But, it was a fun problem. I think this code is a bit more clear.
public class ReplaceLast {
public String deleteLastOccurrence(String fromThis, String word){
int wordLength = word.length();
if(fromThis.startsWith(word + ",")){
return fromThis.substring(wordLength + 1);
}
if(fromThis.endsWith("," + word)){
return fromThis.substring(0, fromThis.length() - wordLength - 1);
}
int index = fromThis.lastIndexOf("," + word + ",");
if(index == -1){
return fromThis;
}
return fromThis.substring(0, index) + fromThis.substring(index+word.length() + 1);
}
#Test
public void testNotThere() {
String actual = deleteLastOccurrence("foo,bar,dog,cat,dog,bird","moose");
assertEquals("foo,bar,dog,cat,dog,bird", actual);
}
#Test
public void testMiddle() {
String actual = deleteLastOccurrence("foo,bar,dog,cat,dog,bird","dog");
assertEquals("foo,bar,dog,cat,bird", actual);
}
#Test
public void testFirst() {
String actual = deleteLastOccurrence("foo,bar,dog,cat,dog,bird","foo");
assertEquals("bar,dog,cat,dog,bird", actual);
}
#Test
public void testLast() {
String actual = deleteLastOccurrence("foo,bar,dog,cat,dog,bird","bird");
assertEquals("foo,bar,dog,cat,dog", actual);
}
#Test
public void testSubword() {
String actual = deleteLastOccurrence("foo,bar,dog,cat,dog,bird","bir");
assertEquals("foo,bar,dog,cat,dog,bird", actual);
}
}

I tried to solve the problem of trimming a string on the first occurrence of a specific word and I didn't care about the original name of the method (deleteLastOccurrence) that is IMO misleading.
The trick to match only single word and not subwords for me is to add two commas before and after the sentence and then check the word with commas.
i.e. ",dog," will be checked against ",foo,bar,dog,cat,dog,bird," for presence.
package gicappa;
public class So {
public static String trimSentenceOnFirstOccurrenceOf(String sentence, String word) {
if (word.isEmpty()) return sentence;
if (!addCommasAround(sentence).contains(addCommasAround(word))) return sentence;
return trimAddedCommasOf(substringOfSentenceUntilEndOfWord(addCommasAround(sentence), addCommasAround(word)));
}
public static String substringOfSentenceUntilEndOfWord(String string, String word) {
return string.substring(0, string.indexOf(word) + word.length());
}
public static String trimAddedCommasOf(String string) {return string.substring(1,string.length()-1);}
public static String addCommasAround(String s) {return "," + s + ","; }
}
and if you'd fancy some testing I used for TDD, here we go:
package gicappa;
import org.junit.Test;
import static gicappa.So.trimSentenceOnFirstOccurrenceOf;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;
public class SoTest {
#Test
public void it_returns_the_same_sentence_for_empty_word() {
assertThat(trimSentenceOnFirstOccurrenceOf("foo,bar,dog,cat,dog,bird", ""), is(equalTo("foo,bar,dog,cat,dog,bird")));
}
#Test
public void it_returns_the_same_sentence_for_not_contained_word() {
assertThat(trimSentenceOnFirstOccurrenceOf("foo,bar,dog,cat,dog,bird", "s"), is(equalTo("foo,bar,dog,cat,dog,bird")));
}
#Test
public void it_returns_the_first_word() {
assertThat(trimSentenceOnFirstOccurrenceOf("foo,bar,dog,cat,dog,bird", "foo"), is(equalTo("foo")));
}
#Test
public void it_returns_the_same_sentence_if_is_matched_the_last_word() {
assertThat(trimSentenceOnFirstOccurrenceOf("foo,bar,dog,cat,dog,bird", "bird"), is(equalTo("foo,bar,dog,cat,dog,bird")));
}
#Test
public void it_trims_after_the_end_of_the_first_matched_word() {
assertThat(trimSentenceOnFirstOccurrenceOf("foo,bar,dog,cat,dog,bird", "dog"), is(equalTo("foo,bar,dog")));
}
#Test
public void it_does_not_trim_for_a_subword_of_a_contained_word() {
assertThat(trimSentenceOnFirstOccurrenceOf("foo,bar,dog,cat,dog,bird", "do"), is(equalTo("foo,bar,dog,cat,dog,bird")));
}
#Test
public void it_does_not_trim_for_a_subword_of_an_already_contained_word() {
assertThat(trimSentenceOnFirstOccurrenceOf("dog,foozzo,foo,cat,dog,bird", "foo"), is(equalTo("dog,foozzo,foo")));
}
}
A wordy refactoring for a more OO class could also be:
package gicappa;
public class Sentence {
private String s;
public Sentence(String sentence) {
this.s = sentence;
}
public String trimOnFirstOccurrenceOf(String word) {
if (word.isEmpty() || csvSentenceContainsWord(word)) return s;
return substringSentenceToEndOf(word);
}
private String substringSentenceToEndOf(String word) {
return addCommasTo(s).substring(1, addCommasTo(s).indexOf(addCommasTo(word)) + addCommasTo(word).length()-1);
}
private boolean csvSentenceContainsWord(String word) {
return !addCommasTo(s).contains(addCommasTo(word));
}
public static String addCommasTo(String s) {return "," + s + ",";}
}
with usage like:
new Sentence("dog,foozzo,foo,cat,dog,bird").trimOnFirstOccurrenceOf("foo"), is(equalTo("dog,foozzo,foo"))

How about this:
public String deleteLastOccurrence(String original, String target){
return original.replace("(^|,)" + target + "(,|$)", "");
}

Here's a try at a non-regex version:
public String trimTo(String in, String matchNoCommas) {
if (in.startsWith(matchNoCommas + ",")) // special check here...
return matchNoCommas;
int idx = in.indexOf("," + matchNoCommas+ ",");
if (idx < 0)
return in;
return in.substring(0, idx + matchNoCommas.length()+1);
}
Provides the same results as the regex version by #Bohemian. Your call as to which is more understandable.

Maybe I'm wrong, but wouldn't this do?
public trimCommaSeparatedListToIncludeFirstOccurrenceOfWord(String listOfWords, String wordToMatch) {
int startOfFirstOccurrenceOfWordToMatch = listOfWords.indexOf(wordToMatch);
int endOfFirstOccurrenceOfWordToMatch = startOfFirstOccurrenceOfWordToMatch + wordToMatch.length() - 1;
return listOfWords.substring(0, endOfFirstOccurrenceOfWordToMatch);
}
Now this might not be what the OP wanted, but I think it's what the OP asked for. Example: f("doggy,cat,bird", "dog") would return "dog".
For full-word matching, I'd regex the sucker as others have suggested.

gonzoc0ding, after reading all responses, IMHO your way of do it is the simpler and cleaner, except that should be corrected this way:
public String deleteLastOccurrence(String original, String target){
String[] arr = original.split(",");
arr = Arrays.copyOfRange(arr,0, Arrays.asList(arr).indexOf(target));
path = StringUtils.join(arr,",");
}
But maybe I have not understand your requirements...

Related

Finding the index of a substring in an existing string without IndexOf method

Currently trying to find a little information on how to find an index of a substring in an existing string. For instance if my String was "HelloWorld" and my Substring passed to my method was "world" the return index would be 5. I don't want to use the indexOf method simply because I want to actually learn how the indexOf method actually works from scratch.
public class TestMiniString
{
public static void main(String[] args)
{
String n1 = new String("Helloworld, welcome");
System.out.println(n1.findIndexOf("wo"));
System.out.println(n1.findIndexOf("we"));
System.out.println(n1.findIndexOf("llo"));
}
public class MiniStr
{
private String str;
public MiniStr(String x)
{
this.str = x;
}
public int findIndexOf(String x)
{
}
}
I believe you want to do something like this..
Edited: this should check if there is a substring in your objects string which is equal to the parameter, and if yes returns the starting index, otherwise return -1
public class TestMiniString {
public static void main(String[] args) {
MiniStr n1 = new MiniStr("Helloworld");
System.out.println(n1.findIndexOf("wo"));
}
public class MiniStr {
private String str;
public MiniStr(String x){
this.str = x;
}
public getStr() {
return this.str;
}
public int findIndexOf(String sub) {
for (int i=0; i<getStr().length(); i++) {
if (getStr().charAt(i) == sub.charAt(0)) {
int sumEq = 1;
for (int j=1; j<sub.length(); j++) {
if (sub.charAt(j) != getStr().charAt(i+j)) break;
else sumEq++;
}
if (sumEq == sub.length()) return i;
}
}
return -1; //in case it is not an actual substring
}
}
You can learn how indexOf method actually works in here
ECMAScript 5.1 (ECMA-262)

Trying to replace a char by another into a map

I'm trying to replace W by OU only if the char before him is at position 0 of the string and if it's a consonnant and only the first W in the String, ie TWITWIC --> TOUITWIC.
Here is my code (tampon is the input i give to the code into my test):
public class Phonkw {
static Map<String, String> consonnantReplace = new HashMap<String, String>();
static {
consonnantReplace.put("BW", "BOU");
consonnantReplace.put("CW", "COU");
consonnantReplace.put("DW", "DOU");
consonnantReplace.put("FW", "FOU");
consonnantReplace.put("GW","GOU");
consonnantReplace.put("HW","HOU");
consonnantReplace.put("JW", "JOU");
consonnantReplace.put("KW", "KOU");
consonnantReplace.put("LW", "LOU");
consonnantReplace.put("MW", "MOU");
consonnantReplace.put("NW", "NOU");
consonnantReplace.put("PW", "POU");
consonnantReplace.put("QW", "QOU");
consonnantReplace.put("RW", "ROU");
consonnantReplace.put("SW", "SOU");
consonnantReplace.put("TW", "TOU");
consonnantReplace.put("VW","VOU");
consonnantReplace.put("WW", "WOU");
consonnantReplace.put("XW","XOU");
consonnantReplace.put("ZW", "ZOU");
}
public static String phonkw1(final String tampon){
if (tampon==null){
return "";
}
if(consonnantReplace.containsKey(tampon)){
return consonnantReplace.get(tampon);
}
return tampon;
}
}
I think i need to substring tampon at (0,1) but i cant get the value in map byt the substring.
EDIT : RESOLVE.
In case you want to stick to your Map solution, you will indeed need to use substring(). For the lookup, you want to go for substring(0, 2) because that will be the first two characters of the String tampon. However, be aware that this will throw StringIndexOutOfBoundsException in case of single-letter-words, so a guard checking the length would be required.
This is your code modified accordingly:
import java.util.*;
public class Phonkw {
static Map<String, String> consonnantReplace = new HashMap<String, String>();
static {
consonnantReplace.put("BW", "BOU");
consonnantReplace.put("CW", "COU");
consonnantReplace.put("DW", "DOU");
consonnantReplace.put("FW", "FOU");
consonnantReplace.put("GW","GOU");
consonnantReplace.put("HW","HOU");
consonnantReplace.put("JW", "JOU");
consonnantReplace.put("KW", "KOU");
consonnantReplace.put("LW", "LOU");
consonnantReplace.put("MW", "MOU");
consonnantReplace.put("NW", "NOU");
consonnantReplace.put("PW", "POU");
consonnantReplace.put("QW", "QOU");
consonnantReplace.put("RW", "ROU");
consonnantReplace.put("SW", "SOU");
consonnantReplace.put("TW", "TOU");
consonnantReplace.put("VW","VOU");
consonnantReplace.put("WW", "WOU");
consonnantReplace.put("XW","XOU");
consonnantReplace.put("ZW", "ZOU");
}
public static String phonkw1(final String tampon){
if (tampon == null){
return "";
}
if (tampon.length() >= 2) {
final String key = tampon.substring(0, 2);
if (consonnantReplace.containsKey(key)) {
return consonnantReplace.get(key) + tampon.substring(2);
}
}
return tampon;
}
public static void main(final String... args) {
for (final String arg : args)
System.out.println(phonkw1(arg));
}
}
You could actually create your Map<String, String> with a loop. If you do not intend to modify the Map during runtime, you can also wrap it with Collections.unmodifiableMap() to prevent it from accidental modification.
And you might fix the spelling mistake, it's consonant, not consonnant.
The code would then look like this:
import java.util.*;
public class Phonkw {
private static final Map<String, String> consonantReplace = createConsonantReplaceMap();
private static Map<String, String> createConsonantReplaceMap() {
final Map<String, String> map = new HashMap<>();
final String consonants = "BCDFGHJKLMNPQRSTVWXZ";
for (final char consonant : consonants.toCharArray())
map.put(consonant + "W", consonant + "OU");
return Collections.unmodifiableMap(map);
}
public static String phonkw1(final String tampon) {
if (tampon == null) return "";
if (tampon.length() < 2) return tampon;
final String key = tampon.substring(0, 2);
if (consonantReplace.containsKey(key))
return consonantReplace.get(key) + tampon.substring(2);
return tampon;
}
public static void main(final String... args) {
for (final String arg : args)
System.out.println(phonkw1(arg));
}
}
You don't really need a Map if all the entries are uniform replacements. In that case you could directly check, like this:
public class Phonkw {
private static final String CONSONANTS = "BCDFGHJKLMNPQRSTVWXZ";
public static boolean isConsonant(final char c) {
return CONSONANTS.indexOf(c) != -1;
}
public static String phonkw1(final String tampon) {
if (tampon == null) return "";
if (tampon.length() < 2) return tampon;
if (tampon.charAt(1) == 'W' && isConsonant(tampon.charAt(0)))
return tampon.charAt(0) + "OU" + tampon.substring(2);
return tampon;
}
public static void main(final String... args) {
for (final String arg : args)
System.out.println(phonkw1(arg));
}
}
With a regular expression, the code could be even simpler:
public class Phonkw {
public static String phonkw1(final String tampon) {
return tampon == null ? "" : tampon.replaceAll("^([BCDFGHJKLMNPQRSTVWXZ])W", "$1OU");
}
public static void main(final String... args) {
for (final String arg : args)
System.out.println(phonkw1(arg));
}
}
The code below should replace anything before 'W' that is a consonant but only if that consonant is at position 0 in the string.
public class Phonkw {
static Map<String, String> consonnantReplace = new HashMap<String, String>();
static {
consonnantReplace.put("BW", "BOU");
consonnantReplace.put("CW", "COU");
consonnantReplace.put("DW", "DOU");
consonnantReplace.put("FW", "FOU");
consonnantReplace.put("GW", "GOU");
consonnantReplace.put("HW", "HOU");
consonnantReplace.put("JW", "JOU");
consonnantReplace.put("KW", "KOU");
consonnantReplace.put("LW", "LOU");
consonnantReplace.put("MW", "MOU");
consonnantReplace.put("NW", "NOU");
consonnantReplace.put("PW", "POU");
consonnantReplace.put("QW", "QOU");
consonnantReplace.put("RW", "ROU");
consonnantReplace.put("SW", "SOU");
consonnantReplace.put("TW", "TOU");
consonnantReplace.put("VW", "VOU");
consonnantReplace.put("WW", "WOU");
consonnantReplace.put("XW", "XOU");
consonnantReplace.put("ZW", "ZOU");
}
public static String phonkw1(String tampon) {
if (tampon == null) {
return "";
}
Iterator<String> it = consonnantReplace.keySet().iterator();
while (it.hasNext()) {
String s = it.next();
if (tampon.indexOf(s) == 0) {
tampon = tampon.replace(s, consonnantReplace.get(s));
}
}
return tampon;
}
}
A regex might be another solution?
You should use a regular expression to solve this issue, check in the comments for a good regex to use
If you want to use a non-regex solution you could consider the following code. You can indeed use a String.substring, or use String.charAt for a single character
public class Phonkw {
public static String phonkw1(final String tampon){
if (tampon==null){
return "";
}
if (tampon.length() > 1 && isConsonant(tampon.charAt(0)) {//the first character is a consonant
if (tampon.charAt(1) == 'W') {//the 2nd character is a W
return tampon.charAt(0) + "OU" + tampon.substring(2); // not an optimal solution..
}
}
return tampon;
}
public static boolean isConsonant(char c) {
return "BCDFGHJKLMNPQRSTVWXZ".indexOf(c) != -1;
}
}

Program which add one char to String, then show result by toString() method and count number of String by length()

I have to create class with String and int fields. Constructor without arguments have to initialize: empty string and 0 value for int. addChar(char) method should let program to add new chars to string(name). toString() method should return this string and length() method have to show number of this chars. I tried something like this:
public class Word {
String name;
int number;
public Word() {
name = "";
number = 0;
}
public char addChar() {
return ;
}
public String toString() {
System.out.println(name);
}
public int length() {
return name.length();
System.out.println (name.length());
}
public static void main(String[] args) {
}
}
But really dont know how to write method which could add one char to String (there's error) and how to write program that could use these methods to show it all works.
Thanks
- A String is Immutable, so you can't change it, when ever you try to change a String actually a new String Object is created on the heap.
- Its better to use StringBuilder or StringBuffer which are Mutable.
- StringBuilder came into existence from Java 5, which is Not Thread-Safe, where as StringBuffer exists before the arrival of StringBuilder, but its Thread-Safe.
//////////////////////Edited Part///////////////////////
Try it this way..........................
public class Word {
StringBuilder name = new StringBuilder();
int number; // Class variable are already intialized to its initial value,
// in the case of int its 0.
// String already has an overridden toString method, so its not needed
public void addChar(String s) {
name.append(s);
}
public String getString(){
return name.toString();
}
public static void main(String[] args) {
Word w = new Word();
System.out.println(w.getString().length());
w.addChar("hello");
System.out.println(w.getString().length());
w.addChar("Hi");
System.out.println(w.getString().length());
}
}
It took a litle bit of refactoring, but here you go:
public class Word {
private String name;
private int number;
public Word() {
name = "";
}
public void addChar(char ch) {
name += ch;
number++;
}
public String toString() {
return name;
}
public int length() {
return number;
}
public static void main(String[] args) {
Word myWord = new Word();
myWord.addChar('H');
System.out.println(myWord);
myWord.addChar('e');
myWord.addChar('l');
myWord.addChar('l');
myWord.addChar('o');
System.out.println(myWord);
System.out.println(myWord.length());
}
}
result:
H
Hello
5
Changes:
method toString does return name.
method length does return number.
I added a small proof of concept in the main method.
I implmented the addChar and changed the return type to void.
I changed the Datatype of name to StringBuilder.
Your code will not compile for at least 2 problems: -
Your toString method is not really returning anything. Rather it is printing your string. Change your method body to return your name.
In your length method, you have unreachable code. You have a sysout statement after return statement that will never be executed.
Now, first you need to solve the above issues.
Then in addChar method, you actually need to pass a char as parameter to add to your string. You are missing it. Also, you don't really need to return the char that you just added. So char return type is not needed. Just void will be OK. As you already have a toString method to get your modified string back.
So, your addChar should look like: -
public void addChar(char ch) {
name += ch;
}
And your modified toString and length method should be like this: -
public String toString() {
return name;
}
public int length() {
return name.length();
}
Rest are all unchanged.
I fixed up some of your code for you.
Notes:
this("", 0) calls the constructor that accepts a String and int.
addChar should return nothing and just add on the character.
toString just returns a string.
Code:
public class Word {
String name;
int number;
public Word() {
this("", 0);
}
public Word(String s) {
this(s, 0);
}
public Word(String s, int i) {
name = s;
number = i;
}
public void addChar(char c) {
name += Character.toString(c);
}
public String toString() {
return name;
}
public int length() {
return name.length();
}
public static void main(String[] args) {
//do stuff
}
}

How to filter words in Java?

I want to check if there are 'bad' words in some cases such as checking IDs in register form. But I do not know how to check it.. The bottom code is what I got far with it.
String words = "admin,administrator,babo,sir,melon";
public boolean checkWord(String input) {
if(something here that i need to find??) return false;
else return true;
}
The pattern of words are divided in comma, and I really need help with it please!
The simplest thing would be to search for a word in a sorted array, like this:
private static String[] WORDS = new String[] {
"admin", "administrator", "babo", "melon", "sir"
};
public boolean checkWord(String input) {
return Arrays.binarySearch(WORDS, input) < 0; // Not found
}
Another example if you want to look for group of words inside your input
public class TestCheckWord {
static String words = "admin,administrator,babo,sir,melon";
public static void main (String args[]){
System.out.println(checkWord("Hello melon"));
System.out.println(checkWord("Hello sir"));
System.out.println(checkWord("Hello you"));
}
public static boolean checkWord(String input) {
String wordArray[] = words.split(",");
for(int i=0; i<wordArray.length; i++){
if(input.indexOf(wordArray[i])>-1)
return true;
}
return false;
}
}
and yet even another way to look for words only if your input contains only one word.(the order in the array doesn't matter in this case.
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class TestCheckWord2 {
public static void main (String args[]){
System.out.println(checkWord("babo"));
System.out.println(checkWord("bobo"));
}
private static String[] WORDS = {"admin", "babo", "melon", "sir", "administrator"};
private static Set<String> mySet = new HashSet<String>(Arrays.asList(WORDS));
public static boolean checkWord(String input) {
return mySet.contains(input);
}
}
public class steve {
static boolean checkWord(String input, String words) {
if(words.contains(input)) {
return true;
}
else {
return false;
}
}
public static void main(String[] args) {
String words = "admin,administrator,babo,sir,melon";
System.out.print(steve.checkWord("babo",words));
}
}

Reverse a string using a recursive void method

So I'm trying to write a method that reverses a given string but the catch is that it has to be a void method rather than a return method which is making this difficult. My code seems logical to me but it doesn't work so I'm hoping someone can help me figure out where I'm going wrong.
public class Reverser {
public String text, revText;
/**
* #param args
*/
public static void main(String[] args) {
Reverser greeting = new Reverser("Buildings");
greeting.reverse();
System.out.println(greeting.getText());
}
public Reverser(String _text){
text = _text;
}
public void reverse(){
int len = text.length();
if(len >= 1){
String last = text.substring(text.length() - 1, text.length());
revText += last;
text = text.substring(0, text.length() - 1);
Reverser loop = new Reverser(text);
loop.reverse();
}
}
public String getText(){
return revText;
}
}
Here's an idea:
public class Reverser {
private int idx;
private String text, revText;
public static void main(String[] args) {
Reverser greeting = new Reverser("Buildings");
greeting.reverse();
System.out.println(greeting.getText());
}
public void reverse() {
if (idx == text.length())
return;
revText = text.charAt(idx) + revText;
idx++;
reverse();
}
public Reverser(String _text) {
idx = 0;
text = _text;
revText = "";
}
public String getText() {
return revText;
}
}
The fundamental difference with respect to your answer, is that I'm using an index attribute to keep track of where exactly I am in the recursion. In that way, I don't have to modify the original text attribute.
A slighty different version to what Oscar Lopez responded is this
public class Sentence{
private String sntce, rvrse;
private int idx;
public Sentence(String sentence){
sntce = sentence;
rvrse = "";
}
/**
A method to reverse a string recursively.
#return void.
*/
void reverse(){
if (idx == sntce.length()){
sntce = rvrse;
return;
}
rvrse = sntce.charAt(idx) + rvrse;
idx++;
reverse();
}
/**
To test reverse gives the appropriate value.
#return the value of sntce.
*/
public String getText(){
return sntce;
}
}
Here's a version that uses as few instance variables as possible. Unfortunately you need at least one instance variable to hold the final result (result). Otherwise the state is passed into each recursive call.
(PS, is this homework?)
public class RecursiveVoidStringReverser {
public static void main(String[] args) {
final RecursiveVoidStringReverser reverser = new RecursiveVoidStringReverser();
reverser.reverse("Welcome to the jungle!");
System.out.println("reverser.result = " + reverser.result());
}
private String result;
public void reverse(String s) {
if ("".equals(s)) {
result = s;
} else {
reverse(s.toCharArray(), 0);
}
}
private void reverse(char[] chars, int index) {
if (index > chars.length / 2) {
result = new String(chars);
} else {
char t = chars[index];
chars[index] = chars[chars.length - index - 1];
chars[chars.length - index - 1] = t;
reverse(chars, index+1);
}
}
public String result() {
return result;
}
}
Given that a string is immutable, you cannot change it in situ. If the only requirement is that there be no return value, and it's okay simply to print out the final string (or to place it into a class variable), then this would work fine for any strings of at least one character:
public static void main(String args[])
{
reverse("", "original string");
}
public static void reverse(String reversed, String original)
{
if(original.length() <= 1)
{
System.out.println(original.charAt(0) + reversed);
// (or set it into a shared variable)
return;
}
reverse(original.charAt(0) + reversed, original.substring(1));
}
This solution is going for procedural simplicity, not memory efficiency. This produces quite an unpleasant memory footprint, essentially creating two in-memory strings for each character in the original. It is, however, very logically simple.
Of course, if you're just dumping out to console, then you can achieve the same thing using an algorithm that's pretty much the same as one with a return value:
public static void reverse(String original)
{
if(original.length() < 1) return;
System.out.print(original.charAt(original.length() - 1));
reverse(original.substring(0, original.length() - 1));
}

Categories

Resources