java linked list works except in one instance

时间:2015-05-24 20:55:19

标签: java unicode junit

I am writing a Linked List in Java that is essentially a mixture of Java's String and StringBuilder classes. I have to test it with JUnit and all of the tests pass, except for the last two, where it passes in a string consisting of every character. In this case the Linked List contains only the first two characters, but has the right length. I am not sure why it doesn't work in this case, but works in other cases where "abcd", "xyzzy", or "This is a very long string." I am not allowed to use string methods except for charAt() in the constructor. Here is my code:

import java.util.Scanner;

public class LString{

  private char letter;
  private LString next;
  private int length;

  public LString(){
  }
  public LString(String original){ //this constructor is where it fails
        if (original != ""){
              Scanner darkly = new Scanner(original).useDelimiter("");
              this.letter = darkly.next().charAt(0);
              this.next = new LString(); 
              LString curr = this.next;
              this.length++;
              while (darkly.hasNext()){
                    curr.next = new LString();
                    curr.letter = darkly.next().charAt(0);
                    curr = curr.next;
                    this.length++;
              }  
        }               
  }
  public int length(){
        return this.length;
  }
  public String toString(){
        StringBuilder temp = new StringBuilder();
        if (this.letter != '\u0000'){
              temp.append(this.letter);
        }
        LString curr = next;
        for (int j = 0; j < this.length; j++){
               if (curr != null && curr.letter != '\u0000'){
                     temp.append(curr.letter);
                     curr = curr.next;
               }
        }     
        return temp.toString();
  }
  public int compareTo(LString anotherLString){
        LString curr = this;
        LString test = anotherLString;
        if (this == null || anotherLString == null){
              return 0;
        }
        for (int q = 0; q <= this.length && q <= anotherLString.length; q++){
              if (curr.letter != test.letter){
                    return curr.letter - test.letter;
              }
              if (curr.next != null && test.next != null){
                    curr = curr.next;
                    test = test.next;
              }
        }
        if (this.length != anotherLString.length){
              return this.length - anotherLString.length;
        }
        return 0;
  }
  @Override
  public boolean equals(Object other) {
        if (other == null || !(other instanceof LString))
              return false;
        else {
              LString otherLString = (LString)other;
              if (compareTo(otherLString) == 0){
                    return true;
              }else{
                    return false;
              }
        }
  }
  public char charAt(int index){
        if (index < 0 || index >= this.length){
              throw new IndexOutOfBoundsException();
        }
        LString curr = findIndex(index, this);
        return curr.letter;
  }
  public void setCharAt(int index, char ch){
        if (index < 0 || index >= this.length){
              throw new IndexOutOfBoundsException();
        }
        LString curr = findIndex(index, this);
        curr.letter = ch;      
  }
  private LString findIndex(int index, LString search){
        LString curr = search;
        for (int l = 0; l < index; l++){
              curr = curr.next;
        }
        return curr;
  }
  public LString substring(int start, int end){
        if (start > end || start < 0 || end > this.length){
              throw new IndexOutOfBoundsException();
        }
        if (start == end){
              return new LString();
        }
        LString curr = new LString(Character.toString(this.charAt(start)));
        int p = start + 1;
        while (p < end){
              LString pete = new LString(Character.toString(this.charAt(p)));
              append(curr, pete);
              p++;
        }
        return curr;
  }
  public LString replace(int start, int end, LString LStr){
        if (start > end || start < 0 || end > this.length){
              throw new IndexOutOfBoundsException();
        }
        LString roger = new LString(LStr.toString());
        if (LStr == null || LStr.letter == '\u0000'){
              replaceHelper(roger);
              return this;
        }

        if (this == null || this.letter == '\u0000'){
              replaceHelper(roger);
              return this;
        }
        if (start == end){  
              if (this.length == 1 && start == 0){
                    LString temp = new LString(LStr.toString() + this.letter);
                    replaceHelper(temp);
                    return this;
              }else if (this.length == 1){
                    LString temp9 = new LString(this.letter + LStr.toString());
                    replaceHelper(temp9);
                    return this;      
              }
              if (end == this.length){
                    LString karl = new LString(this.toString() + roger.toString());
                    replaceHelper(karl);
                    return this;
              }
              if (end < this.length && start != 0){
                    LString ned = findIndex(start - 1, this);
                    LString pup = findIndex(end, this);
                    String batman = "";
                    while (pup.letter != '\u0000'){
                          batman += pup.letter;
                          pup = pup.next;
                    }
                    ned.next = null;
                    LString miranda = new LString(batman);
                    LString urkel = new LString(this.toString() + roger.toString() + miranda.toString());
                    replaceHelper(urkel);
                    return this;
              }
              LString jeff = new LString(roger.toString() + this.toString());
              replaceHelper(jeff);
              return this;
        }
        if (this.length == 1){
              LString temp11 = new LString(LStr.toString());
              replaceHelper(temp11); 
              return this;            
        }
        if (start == 0){
              if (end < this.length){
                    LString patrick = findIndex(end, this);
                    String themaxxxx = "";
                    while (patrick.letter != '\u0000'){
                          themaxxxx += patrick.letter;
                          patrick = patrick.next;
                    }
                    LString boudreau = new LString(themaxxxx);
                    LString yusef = new LString(roger.toString() + boudreau);
                    replaceHelper(yusef);
                    return this;
              }
              LString irvine = findIndex(end, this);
              LString geronimo = new LString(roger.toString() + irvine);
              replaceHelper(geronimo);
              return this;
        }
        LString jurgen = findIndex(start - 1, this);
        LString howard = findIndex(end, this);
        jurgen.next = null;
        String spawn = "";
        while (howard.letter != '\u0000'){
              spawn += howard.letter;
              howard = howard.next;
        }
        LString orion = new LString(spawn);
        LString bonnie = new LString(this.toString() + roger.toString() + orion.toString());
        replaceHelper(bonnie);
        return this;
  }
  private void append(LString curr, LString pete){
        LString yup = curr;
        while (yup.next.next != null){
              yup = yup.next;
        }
        yup.next = pete;
        curr.length++;
  }
  private void replaceHelper(LString help){
        this.letter = help.charAt(0);
        this.length = 1;
        this.next = new LString();
        LString result = this.next;
        for (int t = 1; t < help.length; t++){
                result.letter = help.charAt(t);
                result.next = new LString();
                result = result.next;
                this.length++;
        }      
  }

} and here is the relevant testing code:

 private String allCharsString;

  @Before public void setUp() {
     StringBuilder sb = new StringBuilder(((int)Character.MAX_VALUE) + 10);
     sb.append("}>");
     for (char ch = Character.MIN_VALUE; ch < Character.MIN_SURROGATE; ch++)
        sb.append(ch);
     sb.append("<{");
     allCharsString = sb.toString();
  }

  @Test public void test81aAllChars() {
     LString testLString = new LString(allCharsString);
     assertEquals("Problem with representing all chars",
           allCharsString, testLString.toString());
  }

  @Test public void test81bAllCharsLength() {
     LString testLString = new LString(allCharsString);
     assertEquals("Problem with representing all chars",
           allCharsString.length(), testLString.length());
  }

  @Test public void test81cAllCharReplace() {
     LString testLString = new LString(allCharsString);
     LString testLString2 = new LString(allCharsString);
     int length = allCharsString.length();
     assertEquals("Problem with representing all chars",
           allCharsString + allCharsString,
           testLString.replace(length, length, testLString2).toString());
  }

The first and third test fail, but the second passes. Here is the output:

Running special tests (3 tests)
Starting tests: E.E
Time: 0.131

There were 2 failures:
1) test81aAllChars(LStringTest$LStringSpecialTest)
org.junit.ComparisonFailure: Problem with representing all chars expected:<}>[
!!(everycharacter goes here, in unicode)!! but was:<}>[]>
at org.junit.Assert.assertEquals(Assert.java:115)
        at LStringTest$LStringSpecialTest.test81aAllChars(LStringTest.java:764)
        ... 10 more
2) test81cAllCharReplace(LStringTest$LStringSpecialTest)
org.junit.ComparisonFailure: Problem with representing all chars expected:<}>[
!!(every character goes here, in unicode)!! but was:<}>[]>
at org.junit.Assert.assertEquals(Assert.java:115)
        at LStringTest$LStringSpecialTest.test81cAllCharReplace(LStringTest.java:778)

Can anyone help?

1 个答案:

答案 0 :(得分:0)

我认为我找到了真正的问题,它与字符编码有关。在创建链表后,我验证了构造函数是好的,长度= 55300。然后我进入了重写的toString()方法。通过for循环的第三次迭代失败..... curr.letter IS等于\ u0000。这会导致您绕过指向下一个节点的循环内部,因此在第三次迭代后,curr的值不会更改。你只需在循环中迭代另一个55297左右,什么也不做。这就是为什么toString的返回值是那个小的2个字符的字符串“}&gt;”。我不是charAt()和unicode的专家,但我猜测原始字符串中的第三个字母是编码的,这样扫描仪识别的第一个完整标记就是'\ u1000'。

这就是你的第二次测试通过的原因。你的长度计数器正确递增,但它实际上只是你的构造函数循环执行次数的计数器。当你从toString()获得长度时,你得到值2.

作为一个友好的设计提示,toString()应该使用以下循环条件,因为涉及链接列表:

while(curr != null)
{
    //loop body
}

这样一来,如果在列表创建过程中出现问题,你就会更容易理解它。使用this.length作为循环条件假设您的列表长度和计数器相等,这是一个冒险的假设。

这是一个有效的构造函数:

public LString(String original){ 
    StringBuilder sb = new StringBuilder();
    if (original != ""){
        Scanner darkly = new Scanner(original).useDelimiter("");
        LString currNode = this;
        while (darkly.hasNext()){
            currNode.letter = darkly.next().charAt(0);
            this.length++;
            if (darkly.hasNext()) { //don't add next node if no more chars
                currNode.next = new LString();
                currNode = currNode.next;
            }
        }
    }               
}

这是一个工作toString()循环链表,同时忽略特定字符值作为退出条件

public String toString(){
    StringBuilder temp = new StringBuilder();
    temp.append(this.letter); //assumes you always have at least one character to print
    LString curr = next;
    while (curr != null ){
        temp.append(curr.letter);
        curr = curr.next;
    }

    return temp.toString();
}

我确认这将使JUnit测试test81aAllChars通过。没有时间看你的替换方法以及为什么会失败但是我在这里发现的也会帮助你。祝你好运。