【问题标题】:Compression class error - Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: -1压缩类错误 - 线程“main”中的异常 java.lang.StringIndexOutOfBoundsException:字符串索引超出范围:-1
【发布时间】:2012-11-09 14:57:31
【问题描述】:

我已经为客户端服务器 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() 计算字符串的方式,但它并没有减少错误。

谁能看到我做错了什么?

【问题讨论】:

    标签: java networking tcp compression


    【解决方案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 不为空,否则也要进行空处理。

    【讨论】:

    • 在获得长度之前你必须做空检查
    • @Sura:你是对的。我已经在进行更新,但后来我看到 getWord(word); 在拆分的单词上被调用,所以它不应该为空,因此删除了空检查,但在底部添加了一个注释。
    【解决方案2】:

    发生这种情况是因为您将一个空字符串传递给 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,然后反转结果。因此,对于结尾包含除 A-Z、a-z 或 0-9 之外的任何字符串的任何字符串,此方法都将返回 true。我还把空格算作不是标点符号。

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

    Java 中的 Character 类非常适合进行此类检查,下次您进行类似操作时绝对值得一看。 http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Character.html

    【讨论】:

      【解决方案3】:

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

      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、空或短字符串做好准备

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-06-19
        • 1970-01-01
        • 2015-05-24
        • 2015-06-30
        • 2011-06-21
        • 2013-01-20
        • 1970-01-01
        相关资源
        最近更新 更多