HTML輸入流編碼探測
博學,切問,近思--詹子知(https://blog.csdn.net/zhiqiangzhan)
在項目中經常會需要對Html輸入流進行分析,那麼我們首先就必須確定該文檔的編碼,如果編碼分析錯誤,就會得到一堆的亂碼。而且現在很多WEB Server在返回相應頭的過程中也很少會指定該HTML文檔的編碼,因此我們隻能對它的輸入流就進行分析。判斷的標準之一就是HTML文檔中meta標記中的charset提供的信息,現在基本上大部分文檔都會提供這個head字段,所以,分析這個字段是個簡單而且十分有效的方法,但是,要想得到這個字段,我們必須要拿到文檔的字符內容才可以,而這個時候,它的字符編碼我們還不知道。由於meta標記出現在HTML文檔的頭部,因此我們有理由隻解析這部分字符串,所以我們可以從HTML InputStream讀出部分字節,把它們解碼成一個字符串,然後根據這個字符串信息,我們就可以順利拿到整個文檔的編碼。在這裏,我們使用ISO8859-1為默認的編碼,之所以選擇它,很大的一點是因為它是一種無損失的編碼,一旦我們不能正確的拿出文檔的編碼,也沒有關係,隻要我們知道文檔正確的編碼,根據ISO8859-1編碼後的字符串,使用ISO8859-1解碼後我們就可以得到原來字節數組。import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URL; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.log4j.Logger; public class HtmlInputStreamDecoder { private static final Logger LOGGER = Logger.getLogger(HtmlInputStreamDecoder.class); private static final String ENCODING_TAG = "<meta[^;]+;//s*charset//s*=//s*([^/"//s]+)[^>]*>"; private static final String IGNORE_TAG_REGEX = "<(head|script|style|iframe|comment)[^>]*>.*?<///1>"; private static final String DEFAULT_ENCODING = "iso8859-1"; private static final Pattern EMPTY_LINE = Pattern.compile("/n^//s*$", Pattern.MULTILINE | Pattern.UNIX_LINES); private static final int BLOCK_SIZE = 1024; public String decode(InputStream is) throws IOException { StringBuilder sb = new StringBuilder(); byte[] bytes = new byte[BLOCK_SIZE]; int len = is.read(bytes); String encoding = resolveEncoding(bytes, len); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Current encoding is " + encoding); } sb.append(stripEmptyLine(new String(bytes, 0, len, encoding))); while ((len = is.read(bytes)) > 0) { sb.append(stripEmptyLine(new String(bytes, 0, len, encoding))); } return sb.toString(); } //去除無關的tag,比如Script,style,head等 public String stripIngoreTag(String input) { Pattern ingorePattern = Pattern.compile(IGNORE_TAG_REGEX, Pattern.DOTALL | Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); Matcher m = ingorePattern.matcher(input); return m.replaceAll(""); } //去除多餘空行 protected String stripEmptyLine(String input) { Matcher m = EMPTY_LINE.matcher(input); return m.replaceAll(""); } protected String resolveEncoding(byte[] bytes, int len) throws UnsupportedEncodingException { String encoding = resolveEncoding(bytes); if (encoding == null) { String detector = new String(bytes, 0, len, DEFAULT_ENCODING); Pattern encodingPattern = Pattern.compile(ENCODING_TAG, Pattern.CASE_INSENSITIVE); Matcher m = encodingPattern.matcher(detector); if (m.find()) { encoding = m.group(1); } else { encoding = DEFAULT_ENCODING; } } return encoding; } public String resolveEncoding(byte[] rawBytes) { String result = null; boolean utf16BEBom = false; boolean utf16LEBom = false; boolean utf16BE = false; boolean utf16LE = false; if (rawBytes.length >= 2) { if (((byte) 0xFE == rawBytes[0]) && ((byte) 0xFF == rawBytes[1])) { utf16BEBom = true; } else if ((byte) 0xFF == (rawBytes[0]) && ((byte) 0xFE == rawBytes[1])) { utf16LEBom = true; } } if (rawBytes.length >= 4) { if ((0 != rawBytes[0]) && (0 == rawBytes[1]) && (0 != rawBytes[2]) && (0 == rawBytes[3])) { utf16LE = true; } else if ((0 == rawBytes[0]) && (0 != rawBytes[1]) && (0 == rawBytes[2]) && (0 != rawBytes[3])) { utf16BE = true; } } if (utf16LE) { result = "UTF-16LE"; } else if (utf16BE) { result = "UTF-16BE"; } else if (utf16LEBom) { result = "UTF-16LEBom"; } else if (utf16BEBom) { result = "UTF-16BEBom"; } return result; } public static void main(String[] args) throws IOException { HtmlInputStreamDecoder decoder = new HtmlInputStreamDecoder(); String text = decoder.decode(new URL("https://www.csdn.com/").openStream()); System.out.println(text); System.out.println(decoder.stripIngoreTag(text)); } }
最後更新:2017-04-02 04:01:42
上一篇:
NIST網站_各種權威的信息安全資料
下一篇:
JavaScript核心參考教程--客戶端JavaScript
學習了LINUX下用C語言遍曆文件夾,一些心得
ng2腳手架安裝流程
WEEX 報錯 TypeError: Converting circular structor to JSON 的解決方法
榪愯Eclipse鎻愮ずNo java virtual machine-鍗氬-浜戞爾紺懼尯-闃塊噷浜?
Firefox(火狐)瀏覽器擴展開發初探
Oracle中的JOIN
Linux下串口驅動解析
spring啟動component-scan類掃描加載過程---源碼分析
如何查看Memcache 運行狀態 stats(Status) —— Memcache Telnet 接口
jdk1.5和jdk1.6對於@override支持的區別