Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/399.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何确定字符串是否包含无效的编码字符_Java_String_Unicode_Encoding - Fatal编程技术网

Java 如何确定字符串是否包含无效的编码字符

Java 如何确定字符串是否包含无效的编码字符,java,string,unicode,encoding,Java,String,Unicode,Encoding,使用场景 我们已经实现了一个web服务,我们的web前端开发人员(通过php api)在内部使用该服务来显示产品数据。用户在网站上输入内容(即查询字符串)。网站在内部通过api调用服务 注意:我们使用restlet,而不是tomcat 原始问题 Firefox 3.0.10似乎尊重浏览器中选择的编码,并根据选择的编码对url进行编码。这确实会导致ISO-8859-1和UTF-8的查询字符串不同 我们的网站转发来自用户的输入,而不转换它(它应该转换),因此它可以通过api调用服务,使用包含德语um

使用场景

我们已经实现了一个web服务,我们的web前端开发人员(通过php api)在内部使用该服务来显示产品数据。用户在网站上输入内容(即查询字符串)。网站在内部通过api调用服务

注意:我们使用restlet,而不是tomcat

原始问题

Firefox 3.0.10似乎尊重浏览器中选择的编码,并根据选择的编码对url进行编码。这确实会导致ISO-8859-1和UTF-8的查询字符串不同

我们的网站转发来自用户的输入,而不转换它(它应该转换),因此它可以通过api调用服务,使用包含德语umlauts的查询字符串调用web服务

例如,对于一个查询部分

    ...v=abcädef
如果选择“ISO-8859-1”,则发送的查询部分如下所示

...v=abc%E4def
...v=abc%C3%A4def
但如果选择了“UTF-8”,则发送的查询部分如下所示

...v=abc%E4def
...v=abc%C3%A4def
所需解决方案

在我们控制服务时,因为我们已经实现了它,所以我们希望检查服务器端调用是否包含非utf-8字符,如果是,则以4xx http状态响应

当前解决方案的详细信息

检查每个字符(=字符串.子字符串(i,i+1))

  • 如果“?”的character.getBytes()[0]等于63
  • 如果Character.getType(Character.charAt(0))返回其他_符号
  • 代码

    protected List< String > getNonUnicodeCharacters( String s ) {
      final List< String > result = new ArrayList< String >();
      for ( int i = 0 , n = s.length() ; i < n ; i++ ) {
        final String character = s.substring( i , i + 1 );
        final boolean isOtherSymbol = 
          ( int ) Character.OTHER_SYMBOL
           == Character.getType( character.charAt( 0 ) );
        final boolean isNonUnicode = isOtherSymbol 
          && character.getBytes()[ 0 ] == ( byte ) 63;
        if ( isNonUnicode )
          result.add( character );
      }
      return result;
    }
    
    而且它不会抛出一个非法的argumentexception信号,

    将解码为给定的编码。这应该适当地标记错误。然而,文件指出:

    这个解码器有两种可能的方法来处理非法字符串。它可以不使用非法字符,也可以抛出IllegalArgumentException。解码器采用哪种方法取决于实现

    所以你应该试试看。另请注意(来自decode()方法文档):

    声明应使用UTF-8。不这样做可能会导致不兼容

    所以还有别的事情要考虑


    编辑:Apache Commons声称会对错误编码抛出适当的异常。

    您需要从一开始就设置字符编码。尝试发送适当的内容类型标题,例如内容类型:text/html;charset=utf-8以修复正确的编码。Web服务的标准一致性。检查您的响应标题

    此外,在服务器端,如果浏览器没有正确处理服务器发送的编码,则通过分配新字符串强制编码。还可以通过执行单个each_byte&0x80检查编码的utf-8字符串中的每个字节,验证结果是否为非零

    
    boolean utfEncoded = true;
    byte[] strBytes = queryString.getBytes();
    for (int i = 0; i < strBytes.length(); i++) {
        if ((strBytes[i] & 0x80) != 0) {
            continue;
        } else {
            /* treat the string as non utf encoded */
            utfEncoded = false;
            break;
        }
    }
    
    String realQueryString = utfEncoded ?
        queryString : new String(queryString.getBytes(), "iso-8859-1");
    
    
    布尔值=真;
    字节[]strBytes=queryString.getBytes();
    对于(int i=0;i

    还有,我希望它能对你有所帮助。

    我问了同样的问题

    我最近找到了一个解决方案,对我来说效果很好。你可能想试试看。这是你需要做的

  • 将URI编码保留为拉丁语-1。在Tomcat上,将URIEncoding=“ISO-8859-1”添加到server.xml中的连接器
  • 如果您必须手动进行URL解码,也可以使用拉丁语1作为字符集
  • 使用fixEncoding()函数修复编码
  • 例如,要从查询字符串中获取参数

      String name = fixEncoding(request.getParameter("name"));
    
    你可以一直这样做。未更改编码正确的字符串

    代码见附件。祝你好运

     public static String fixEncoding(String latin1) {
      try {
       byte[] bytes = latin1.getBytes("ISO-8859-1");
       if (!validUTF8(bytes))
        return latin1;   
       return new String(bytes, "UTF-8");  
      } catch (UnsupportedEncodingException e) {
       // Impossible, throw unchecked
       throw new IllegalStateException("No Latin1 or UTF-8: " + e.getMessage());
      }
    
     }
    
     public static boolean validUTF8(byte[] input) {
      int i = 0;
      // Check for BOM
      if (input.length >= 3 && (input[0] & 0xFF) == 0xEF
        && (input[1] & 0xFF) == 0xBB & (input[2] & 0xFF) == 0xBF) {
       i = 3;
      }
    
      int end;
      for (int j = input.length; i < j; ++i) {
       int octet = input[i];
       if ((octet & 0x80) == 0) {
        continue; // ASCII
       }
    
       // Check for UTF-8 leading byte
       if ((octet & 0xE0) == 0xC0) {
        end = i + 1;
       } else if ((octet & 0xF0) == 0xE0) {
        end = i + 2;
       } else if ((octet & 0xF8) == 0xF0) {
        end = i + 3;
       } else {
        // Java only supports BMP so 3 is max
        return false;
       }
    
       while (i < end) {
        i++;
        octet = input[i];
        if ((octet & 0xC0) != 0x80) {
         // Not a valid trailing byte
         return false;
        }
       }
      }
      return true;
     }
    
    公共静态字符串固定编码(字符串1){
    试一试{
    字节[]字节=1.getBytes(“ISO-8859-1”);
    如果(!validUTF8(字节))
    返回拉丁语1;
    返回新字符串(字节,“UTF-8”);
    }捕获(不支持的编码异常e){
    //不可能,不受限制地扔
    抛出新的IllegalStateException(“无拉丁文1或UTF-8:+e.getMessage());
    }
    }
    公共静态布尔validUTF8(字节[]输入){
    int i=0;
    //检查物料清单
    如果(input.length>=3&&(input[0]&0xFF)==0xEF
    &&(输入[1]&0xFF)==0xBB&(输入[2]&0xFF)==0xBF){
    i=3;
    }
    内端;
    对于(int j=input.length;i
    编辑:由于各种原因,您的方法不起作用。当存在编码错误时,您不能指望从Tomcat得到什么。有时你会� 或其他时候,您不会得到任何结果,getParameter()返回null。假设您可以检查“?”,那么您的查询字符串包含有效的“?”

    此外,你不应该拒绝任何请求。这不是用户的错。正如我在最初的问题中提到的,浏览器可以用UTF-8或拉丁语-1对URL进行编码。用户没有控制权。你需要两者都接受。将servlet更改为Latin-1将保留所有字符,即使它们是错误的,这样我们就有机会修复它或将其丢弃


    我在这里发布的解决方案并不完美,但它是迄今为止我们找到的最好的解决方案

    我一直在研究一个类似的“猜测编码”问题。最好的解决方案是了解编码。除此之外
    module Encoding
        UTF8RGX = /\A(
            [\x09\x0A\x0D\x20-\x7E]            # ASCII
          | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
          |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
          | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
          |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
          |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
          | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
          |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
        )*\z/x unless defined? UTF8RGX
    
        def self.utf8_file?(fileName)
          count = 0
          File.open("#{fileName}").each do |l|
            count += 1
            unless utf8_string?(l)
              puts count.to_s + ": " + l
            end
          end
          return true
        end
    
        def self.utf8_string?(a_string)
          UTF8RGX === a_string
        end
    
    end
    
     CharsetDecoder UTF8Decoder =
          Charset.forName("UTF8").newDecoder().onMalformedInput(CodingErrorAction.REPORT);
    
    value = value.replaceAll("\\p{Cntrl}", "");
    
    CharsetDecoder ebcdicDecoder = Charset.forName("IBM1047").newDecoder();
    ebcdicDecoder.onMalformedInput(CodingErrorAction.REPORT);
    ebcdicDecoder.onUnmappableCharacter(CodingErrorAction.REPORT);
    
    CharBuffer out = CharBuffer.wrap(new char[3200]);
    CoderResult result = ebcdicDecoder.decode(ByteBuffer.wrap(bytes), out, true);
    if (result.isError() || result.isOverflow() ||
        result.isUnderflow() || result.isMalformed() ||
        result.isUnmappable())
    {
        System.out.println("Cannot decode EBCDIC");
    }
    else
    {
        CoderResult result = ebcdicDecoder.flush(out);
        if (result.isOverflow())
           System.out.println("Cannot decode EBCDIC");
        if (result.isUnderflow())
            System.out.println("Ebcdic decoded succefully ");
    }