1

クライアントサーバーのTCPデータ接続用にこの単純な圧縮クラスを作成しましたが、ビルドエラーはなく、すべて問題なく表示されますが、修正できない実行時エラーが発生します。私が得ているエラーは、スレッド「メイン」の例外です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

これは、空の文字列を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 を返します。スペースも句読点ではないと数えています。

オラクルが「isPunctuation」メソッドを入れることを考えていれば、これはさらに簡単になります!

Java の Character クラスは、このようなチェックに非常に優れており、次回同様のことを行うときに確認する価値があります。 http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Character.html

于 2013-11-16T00:11:50.767 に答える
1

あなたstrlength 0(空の文字列) またはlength 1? その場合str = str.substring(length -2,length-1);は例外になります。

部分文字列を実行する前に、長さチェックを行う必要があります。

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

あなたは1文字だけを取得しようとしているので、次のように簡単にできると思います:

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

null でないことを確認してくださいstr。それ以外の場合は、null 処理も入れてください。

于 2012-11-09T15:04:42.507 に答える
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;
    }
}

一般に、文字列操作は遅いので避けるようにしてください。また、部分文字列または文字列インデックスを使用する必要がある場合は、常に null、空、または短い文字列に備えてください。

于 2012-11-09T15:04:18.730 に答える