1

我已经为客户端服务器 TCP 数据连接创建了这个简单的压缩类,对我来说一切都很好,没有构建错误,但是我遇到了一个无法纠正的运行时错误。我得到的错误是线程“main”java.lang.StringIndexOutOfBoundsException中的异常:字符串索引超出范围:-1。

代码:

import java.io.Serializable;
import java.util.ArrayList;

public class CompressedMessage implements Serializable
{   // this instance variable will store the original, compressed and decompressed message
    private String message;

    public CompressedMessage(String message)
    {   
        // begin by coding this method first - initialise instance variable message with the original message
        this.message = message;
    }

    public String getMessage()
    {   
        return this.message;

    }

    private boolean punctuationChar(String str)
    {   
        // Hint: check if the last character in the string is a punctuation
        int length = str.length();
        str = str.substring(length -2,length-1);

        if(str.equals(",") || str.equals("!") || str.equals(".") || str.equals("?"))
        {
            return true;
        }
        else
        {
            return false;
        }

    }

    private String getWord(String str)
    {   // Hint: if last character in string is punctuation then remove 

    if(punctuationChar(str)== true)
    {
        //remove punctuation of last char
        str = str.substring(0,str.length()-1);
    }

        return str;
    }


    public void compress()
    {   /* read through section 3 of the practical 5 document 
           to get you started. This is called by the server, 
           have a look at the server code where it is called */ 
        ArrayList<String> newMessage = new ArrayList<String>();


        String[] words = message.split(" ");  

        for (String word : words)  
        {  
            getWord(word);
            //if word has already appeared replace with position of previous word
            if(newMessage.contains(word))
            {
                String str = Integer.toString(newMessage.indexOf(word));
                str = str + " ";
                newMessage.add(str);
            }
            else
            {
                word = word + "";
                newMessage.add(word);
            }

         //if word had a punctuation at the end add it back in
         //System.out.println(word);  
        }  

            this.message = newMessage.toString();
            System.out.println("****************COMPRESSING*****************");
            System.out.println(newMessage);

    }

    public void decompress()
    {   /* read through section 3 of the practical 5 document 
           to get you started. This is called by the client,
           have a look at the client code where it is called */
           ArrayList<String> decompMessage = new ArrayList<String>();

           String[] words = message.split(" ");


           for (String word : words)  
        {  
            getWord(word);

            if(word.substring(0,1).matches("[0-9]"))
            {
              int num = Integer.parseInt(word);
              decompMessage.add(decompMessage.get(num));

            }
            else
            {
                decompMessage.add(word);
            }
        }

        this.message = decompMessage.toString();
        System.out.println("****************DECOMPRESSING*****************");
            System.out.println(decompMessage);  

    }
}

错误:

Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: -1
    at java.lang.String.substring(String.java:1952)
    at CompressedMessage.punctuationChar(CompressedMessage.java:24)
    at CompressedMessage.getWord(CompressedMessage.java:40)
    at CompressedMessage.compress(CompressedMessage.java:61)
    at P5_Server.waitForData(P5_Server.java:72)
    at P5_Server.main(P5_Server.java:159)

我尝试更改基于 length() 计算字符串的方式,但它并没有减少错误。

谁能看到我做错了什么?

4

3 回答 3

1

如果你strlength 0(空字符串)或length 1?在这种情况下str = str.substring(length -2,length-1);将导致异常。

您需要在执行子字符串之前进行长度检查:

    if(length > 1){
        str = str.substring(length-2,length-1);
    }

由于您只想获得一个角色,我认为您可以简单地执行以下操作:

    if(length > 1){
        str = String.valueOf(str.charAt(length-2))
    }

请确保它str不为空,否则也要进行空处理。

于 2012-11-09T15:04:42.507 回答
1

发生这种情况是因为您将一个空字符串传递给punctuationChar

哦,由于您只是使用 str 中的最后一个字符,因此将其转换为字符可能更容易。

试试这个:

private boolean punctuationChar(String str) {
       if (str.length() > 0) {
           char lastChar = str.charAt(lastChar.length() - 1);

           // Returns true if the character is anything other than a letter, digit or space
           return !(Character.isLetterOrDigit(lastChar)) || Character.isWhitespace(lastChar);
       }
       else {
           return false;
       }
   }
}

我在这里使用 isLetterOrDigit,然后反转结果。因此,对于结尾包含除 AZ、az 或 0-9 以外的任何字符串的任何字符串,此方法都将返回 true。我还将空格算作不是标点符号。

如果 Oracle 考虑放入“isPunctuation”方法,这将更容易!

Java 中的 Character 类非常适合这样的检查,下次你做类似的事情时绝对值得一看。 http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Character.html

于 2013-11-16T00:11:50.767 回答
0

您可以使标点符号检查更容易:

private boolean punctuationChar(String str) {   
    if (str != null && str.length() > 0) {
        char c = str.charAt(str.length()-1);
        return c == '.' || c =='?'||c==',' || c =='!';
    } else {
        return false;
    }
}

一般来说,尽量避免字符串操作,因为它们很慢。如果您需要使用子字符串或字符串索引,请始终确保为空字符串、空字符串或短字符串做好准备

于 2012-11-09T15:04:18.730 回答