4
\$\begingroup\$

I am a Spanish programming teacher in a vocational training course and we are studying arrays. In order to practice and to get the students familiarized with some methods of theString class, I proposed them to reinvent the wheel, implementing some methods of theString class usingchar arrays.

This is the solution that I will provide to my students. The lack of comments is because the solution will be explained in class.

package es.programacion1k.arrays;import java.util.Arrays;//Using char arrays from strings with the String.toCharArray () function implement the following methods//length//indexOf//charAt(index)//lastIndexOf(ch);//replace(oldChar, newChar)//substring(beginIndex, endIndex)//substring(beginIndex)//equals(anObject)//trim();//concat(str)//endsWith(suffix)//contains(s)//indexOf(str)//split("-");public class MyStringMethods {public static void main(String[] args) {    String empty = "";    String ordinary = "Ordinary Test String";    System.out.printf("String Class Method - String: \"%s\" Length: %d%n", empty, empty.length());    System.out.printf("String Class Method - String: \"%s\" Length: %d%n", ordinary, ordinary.length());    System.out.printf("myMethod            - String: \"%s\" Length: %d%n", empty, myLength(empty));    System.out.printf("myMethod            - String: \"%s\" Length: %d%n", ordinary, myLength(ordinary));    char characterToFind = 'N';    String template = "indexOf   - String: \"%s\" character: %c position: %d%n";    String myTemplate = "myIndexOf - String: \"%s\" character: %c position: %d%n";    System.out.printf(template, empty, characterToFind, empty.indexOf(characterToFind));    System.out.printf(myTemplate, empty, characterToFind, myIndexOf(empty, characterToFind));    System.out.printf(template, ordinary, characterToFind, ordinary.indexOf(characterToFind));    System.out.printf(myTemplate, ordinary, characterToFind, myIndexOf(ordinary, characterToFind));    int position = 14;    template = "charAt - String: \"%s\" position: %d character: %c%n";    myTemplate = "myCharAt - String: \"%s\" position: %d character: %c%n";    // System.out.printf(plantilla,StringVacia,position,StringVacia.charAt(position));    // System.out.printf(myPlantilla,StringVacia,position,myCharAt(StringVacia,position));    System.out.printf(template, ordinary, position, ordinary.charAt(position));    System.out.printf(myTemplate, ordinary, position, myCharAt(ordinary, position));    characterToFind = 'e';    template = "lastIndexOf   - String: \"%s\" character: %c position: %d%n";    myTemplate = "myLastIndexOf - String: \"%s\" character: %c position: %d%n";    System.out.printf(template, empty, characterToFind, empty.lastIndexOf(characterToFind));    System.out.printf(myTemplate, empty, characterToFind, myLastIndexOf(empty, characterToFind));    System.out.printf(template, ordinary, characterToFind, ordinary.lastIndexOf(characterToFind));    System.out.printf(myTemplate, ordinary, characterToFind, myLastIndexOf(ordinary, characterToFind));    char characterBefore = 'e';    char characterAfter = 'E';    template = "replace   - String: \"%s\" characterBefore: %c characterAfter: %c StringAfter: \"%s\"%n";    myTemplate = "myReplace - String: \"%s\" characterBefore: %c characterAfter: %c StringAfter: \"%s\"%n";    System.out.printf(template, empty, characterBefore, characterAfter,            empty.replace(characterBefore, characterAfter));    System.out.printf(myTemplate, empty, characterBefore, characterAfter,            myReplace(empty, characterBefore, characterAfter));    System.out.printf(template, ordinary, characterBefore, characterAfter,            ordinary.replace(characterBefore, characterAfter));    System.out.printf(myTemplate, ordinary, characterBefore, characterAfter,            myReplace(ordinary, characterBefore, characterAfter));    int startPosition = 4;    int endPosition = 13;    template = "subString(start,end) - String: \"%s\" start: %d end: %d Result: %s%n";    myTemplate = "mySubString(start,end) - String: \"%s\" start: %d end: %d Result: %s%n";    // System.out.printf(plantilla,vacia,positionInicial,positionFinal,vacia.substring(positionInicial,    // positionFinal));    // System.out.printf(myPlantilla,vacia,positionInicial,positionFinal,mySubstring(vacia,positionInicial,    // positionFinal));    System.out.printf(template, ordinary, startPosition, endPosition,            ordinary.substring(startPosition, endPosition));    System.out.printf(myTemplate, ordinary, startPosition, endPosition,            mySubstring(ordinary, startPosition, endPosition));    startPosition = 4;    template = "subString(start) - String: \"%s\" start: %d Result: %s%n";    myTemplate = "mySubString(start) - String: \"%s\" start: %d Result: %s%n";    // System.out.printf(plantilla,vacia,positionInicial,vacia.substring(positionInicial));    // System.out.printf(myPlantilla,vacia,positionInicial,mySubstring(vacia,positionInicial));    System.out.printf(template, ordinary, startPosition, ordinary.substring(startPosition));    System.out.printf(myTemplate, ordinary, startPosition, mySubstring(ordinary, startPosition));    String second = "Ordinary Test String";    template = "equals(str) - String: \"%s\" Second String: \"%s\" Result: %b%n";    myTemplate = "myEquals(str) - String: \"%s\" Second String: \"%s\" Result: %b%n";    System.out.printf(template, empty, second, empty.equals(second));    System.out.printf(myTemplate, empty, second, myEquals(empty, second));    System.out.printf(template, ordinary, second, ordinary.equals(second));    System.out.printf(myTemplate, ordinary, second, myEquals(ordinary, second));    String withWhiteSpaces = "  Test     ";    template = "trim() - String: \"%s\" Resultado: \"%s\"%n";    myTemplate = "myTrim() - String: \"%s\" Resultado: \"%s\"%n";    System.out.printf(template, empty, empty.trim());    System.out.printf(myTemplate, empty, myTrim(empty));    System.out.printf(template, withWhiteSpaces, withWhiteSpaces.trim());    System.out.printf(myTemplate, withWhiteSpaces, myTrim(withWhiteSpaces));    String added = " more characters";    template = "concat(str) - String: \"%s\" Added: \"%s\" Result: \"%s\"%n";    myTemplate = "myConcat(str) - String: \"%s\" Added: \"%s\" Result: \"%s\"%n";    System.out.printf(template, empty, added, empty.concat(added));    System.out.printf(myTemplate, empty, added, myConcat(empty, added));    System.out.printf(template, ordinary, added, ordinary.concat(added));    System.out.printf(myTemplate, ordinary, added, myConcat(ordinary, added));    String ending = "String";    template = "endsWith(str) - String: \"%s\" ending: \"%s\" Result: \"%b\"%n";    myTemplate = "myEndsWith(str) - String: \"%s\" ending: \"%s\" Result: \"%b\"%n";    System.out.printf(template, empty, ending, empty.endsWith(ending));    System.out.printf(myTemplate, empty, ending, myEndsWith(empty, ending));    System.out.printf(template, ordinary, ending, ordinary.endsWith(ending));    System.out.printf(myTemplate, ordinary, ending, myEndsWith(ordinary, ending));    String toFind = "String";    template = "indexOf(str) - String: \"%s\" tofind: \"%s\" Result: \"%d\"%n";    myTemplate = "myIndexOf(str) - String: \"%s\" tofind: \"%s\" Result: \"%d\"%n";    System.out.printf(template, empty, toFind, empty.indexOf(toFind));    System.out.printf(myTemplate, empty, toFind, myIndexOf(empty,toFind));    System.out.printf(template, ordinary, toFind, ordinary.indexOf(toFind));    System.out.printf(myTemplate, ordinary, toFind, myIndexOf(ordinary,toFind));    String separator = "o";    template = "split   - String: \"%s\" character: %s%n";    myTemplate = "mySplit - String: \"%s\" character: %s%n";//      System.out.printf(plantilla, vacia, separador, vacia.split(separador));//      System.out.printf(myPlantilla, vacia, characterBuscado, myIndexOf(vacia, characterBuscado));    System.out.printf(template, ordinary, separator);    for(String s:ordinary.split(separator)){        System.out.println(s);    }    System.out.printf(myTemplate, ordinary, separator);    for(String s:mySplit(ordinary,separator)){        System.out.println(s);    }}static int myLength(String s) {    char[] characters = s.toCharArray();    return characters.length;}static int myIndexOf(String s, char c) {    char[] characters = s.toCharArray();    for (int i = 0; i < characters.length; i++) {        if (characters[i] == c) {            return i;        }    }    return -1;}static int myCharAt(String s, int pos) {    char[] characters = s.toCharArray();    return characters[pos];}static int myLastIndexOf(String s, char c) {    char[] characters = s.toCharArray();    for (int i = characters.length - 1; i >= 0; i--) {        if (characters[i] == c) {            return i;        }    }    return -1;}static String myReplace(String s, char before, char after) {    char[] characters = s.toCharArray();    for (int i = 0; i < s.length(); i++) {        if (characters[i] == before) {            characters[i] = after;        }    }    return new String(characters);}private static String mySubstring(String s, int initialPosition, int finalPosition) {    char[] characters = s.toCharArray();    int lengthSubString = finalPosition - initialPosition;    char[] result = new char[lengthSubString];    for (int i = 0; i < lengthSubString; i++) {        result[i] = characters[i + initialPosition];    }    return new String(result);}private static String mySubstring(String String, int positionInicial) {    return mySubstring(String, positionInicial, String.length());}static boolean myEquals(String first, String second) {    char[] charactersFirst = first.toCharArray();    char[] charactersSecond = second.toCharArray();    if (charactersFirst.length != charactersSecond.length) {        return false;    }    for (int i = 0; i < charactersFirst.length; i++) {        if (charactersFirst[i] != charactersSecond[i]) {            return false;        }    }    return true;}static String myTrim(String s) {    char[] characters = s.toCharArray();    if (characters.length == 0) {        return "";    }    int initialWhiteSpaces = 0;    while (Character.isWhitespace(characters[initialWhiteSpaces])) {        initialWhiteSpaces++;    }    int finalWhiteSpaces = characters.length - 1;    while (Character.isWhitespace(characters[finalWhiteSpaces])) {        finalWhiteSpaces--;    }    return mySubstring(s, initialWhiteSpaces, finalWhiteSpaces + 1);}static String myConcat(String s, String added) {    char[] characters = s.toCharArray();    char[] charactersAdded = added.toCharArray();    char[] result = new char[characters.length + charactersAdded.length];    int i;    for (i = 0; i < characters.length; i++) {        result[i] = characters[i];    }    for (int j = 0; j < charactersAdded.length; j++) {        result[i + j] = charactersAdded[j];    }    return new String(result);}static boolean myEndsWith(String s,String ending){    char[] characters = s.toCharArray();    char[] endingCharacters = ending.toCharArray();    if(characters.length<endingCharacters.length){        return false;    }    for(int i=characters.length-1,j=endingCharacters.length-1;j>=0;j--,i--){        if(characters[i]!=endingCharacters[j]){            return false;        }    }    return true;}static int myIndexOf(String s,String toFind){    char[] characters = s.toCharArray();    char[] charactersToFind = toFind.toCharArray();    if(characters.length<charactersToFind.length){        return -1;    }    int lookingAtPosition=0;    do{//          System.out.println("myrando: "+characters[positionmyrada]);        int iguales=0;        int i=lookingAtPosition;        int j=0;        while(j<charactersToFind.length){//              System.out.print("entro "+i+" "+j);            if(characters[i]!=charactersToFind[j]){                break;            }            i++;            j++;        }        if(j==charactersToFind.length){//              System.out.println("Encontrado en: "+positionmyrada);            return lookingAtPosition;        }        lookingAtPosition++;    }while(lookingAtPosition<=characters.length-charactersToFind.length);    return -1;}static boolean myContains(String s,String toFind){    return myIndexOf(s,toFind)!=-1;}static String[] mySplit(String s,String splitter){    char[] characters = s.toCharArray();    char separator=splitter.charAt(0);    int tokens=1;    for(int i=0;i<characters.length-1;i++){        if(characters[i]==separator){            tokens++;        }    }    char[][] result=new char[s.length()][];    int indexString = 0;    for (int i = 0; i < tokens; i++) {        int indexSubString = 0;        while (characters[indexString] != separator) {            if (indexString == characters.length - 1) {                indexSubString++;                break;            }            indexString++;            indexSubString++;        }        result[i]=new char[indexSubString];        indexString++;    }    indexString = 0;    for (int i = 0; i < tokens; i++) {        int indiceSubString = 0;        while (characters[indexString] != separator) {            result[i][indiceSubString] = characters[indexString];            if (indexString == characters.length - 1) {                break;            }            indexString++;            indiceSubString++;        }        indexString++;    }    String[] finalResult=new String[tokens];    for(int i=0;i<tokens;i++){        finalResult[i]=new String(result[i]);    }    return finalResult;    }}

Thesplit function (with a character as a separator) is really difficult to implement and I do not ask the students to do it, it's just an example.

We have only studied what is used in the program.

Jamal's user avatar
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
askedJan 11, 2017 at 12:15
Miguel-David's user avatar
\$\endgroup\$

1 Answer1

2
\$\begingroup\$

Object-oriented

The first comment, is that all of the methods arestatic, and their names begin withmy.... Java is an object-oriented language, so in order to re-implement aString class working on character arrays, it would be preferable to create a newMyString class. On that class, you can then have the typical methodslength() ortrim(), with a clear name (instead of having them prefixed withmy).

Consider having the starting template of:

public class MyString {    private char[] characters;    public MyString(String str) {        characters = str.toCharArray();    }    public int length() {        // ...    }}

Then the rest of the code can operate on the character array alone, without interference from aString parameter to a static method. The big advantage with this approach is that you gain

Unit testing

Right now, all of the test code is written inside themain method. While this can work during development to easily test some scenarios, having a proper unit test, written with JUnit or TestNG for example, is preferable: you can create this test class on your side, and verify automatically the all of the students submissions with it.

A simple JUnit test would be

import static org.junit.Assert.assertEquals;import org.junit.Test;public class MyStringTest {    @Test    public int testLengthOfEmptyString() {        MyString str = new MyString("");        assertEquals(0, str.length());    }    // more tests (one with a non empty string for example)}

The methods

The currently all follow the pattern of fetching the character array from the given String parameter. When refactoring this to theMyString class having a character array field, this is simplified. Instead of

static int myLength(String s) {    char[] characters = s.toCharArray();    return characters.length;}

you can directly have

public int length() {    return characters.length;}

Keep in mind that the methods differ slightly from the ones of theString class (charAt methodreturns achar instead of anint, orindexOf takes anint as parameterinstead of achar, etc.), although it may not matter since the point is to learn arrays. I also noticed that some of them areprivate (likemySubstring); was that the intent? They should probably be made public and to be implemented by the student.

Be careful with the implementation oftrim(), it does not have the same behaviour asString.trim(). For example, consider the following String having aparagraph separator (e.g.\u2029), and a tabulation character (to see the difference):

System.out.println("\u2029\tABAB".trim());  // prints "    ABAB"System.out.println(myTrim("\u2029\tABAB")); // prints "ABAB"

This is because the rewrittentrim() removes all Java white space characters as returned byisWhitespace, but thetrim() built-in considers all characters below' '.

A note regardingsplit as well: currently it fails if it is passed an empty String. That case should be taken care of: it could be by returning an array of all the characters, like the built-insplit does, but the intent for this method is more to accept achar separator as parameter, instead of a String, because what it does is split by a single character.

The methodsplit can be implemented in a more direct way, still reasoning on the character arrays: step 1 is to calculate the total number of tokens and step 2 is to loop over the characters, keeping the running index where a character equal to the separator is found (starting at 0) and taking the substring between that index and the next one (I usedArrays.copyOfRange in the snippet below, but that can easily be replaced with a for loop if you wish to keep it strictly without utility methods).

public String[] split(char separator) {    int length = characters.length;    int tokens = 0;    for (char ch : characters) {        if (ch == separator) {            tokens++;        }    }    String[] result = new String[tokens + 1];    int resultIndex = 0;    int startIndex = 0;    for (int i = 0; i < length; i++) {        if (characters[i] == separator) {            result[resultIndex] = new String(Arrays.copyOfRange(characters, startIndex, i));            startIndex = i + 1; // + 1 to skip the separator            resultIndex++;        }    }    // to take the last part into account    result[resultIndex] = new String(Arrays.copyOfRange(characters, startIndex, length));    return result;}

The rest of the code is fine; just make sure to remove the unused variable (int iguales = 0;) and commented-out code inindexOf(toFind).

answeredJan 11, 2017 at 14:28
Tunaki's user avatar
\$\endgroup\$
1
  • \$\begingroup\$Thank you very much for your appropiate comment. It was really helpful\$\endgroup\$CommentedJan 17, 2017 at 17:37

You mustlog in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.