PDA

View Full Version : Charset Detector



Vesal64
سه شنبه 08 بهمن 1387, 20:49 عصر
با سلام.
من یک برنامه نویس جاوا هستم.
کرست دتکتور ,CharsetDetector, Chraset Detector, Charset Detect, Detect Charset : با عرض پوزش این کلمات رو نوشتم تا اگر کسی هر کلمه ای را در این مورد search کرد این صفحه رو براش بیاره.

من یک مشکل در مورد detect کردن نوع charset یک inputstream داشتم واین مشکل رو تا حدودی حل کردم. خواستم اگر کسی این مشکل رو داشت بتونه از این راه حل ها استفاده کنه چون من خودم خیلی تو سایتهای انگلیسی گشتم تا یک راه پیدا کردم. گرچه خیلی از راه ها مشکل داشت یا jar فایل هایی که گذاشته بودند درست کار نمی کرد ولی چندتا از اون ها کم و بیش درست کار می کردند. البته این راه ها هم قطعی نیستند ولی من تا اینجا ازشون جواب گرفتم و می تونم بگم که تقریبا ۹۰ درصد شماها به اندازه من با صفحات متنوع از نظر نوع charset مواجه نیستید و این راه حل ها جوابگوی شما هست.

۱. بهترین راه ولی ظاهرا تا حدودی نشدنی :
توی هر فایلی که حاوی یک سری اطلاعات هست. editor مربوطه حالا هر چی می خواد باشه ۲ تا ۶ بایت اول اون فایل یا stream رو اختصاص به تعیین کردن نوع charset مربوطه می کنه مثلا FFFF بیان گر charset فلان هست. من خیلی گشتم که کلیه charset ها رو پیدا کنم ولی زهی خیال باطل. فقط برای چند charset معروف document وجود داشت از جمله UTFها. تازه همه editor ها از این استانداردها استفاد ه نمی کنند و من تناقض در این مورد رو بعضا می دیدم.
به هر حال اگر کسی تونست کل این charsetها که استانداردهاش فقط ۳۰ تا ۴۰ مورد هس ترو در بیاره و یک jar فایل و source اون رو تو یکی از سایتهای فارسی بذاره کار خیلی مفیدی کرده چون سریعترین راه هست.

۲. خوب من خودم واسه حل این مشکل یک متد نوشتم که در زیر اونو گذاشتم. کند هست ولی چاره ای نداشتم البته اگه خود inputstream شما سالم باشه کاملا جواب می ده.
برای اینکه یک مقدار سریعتر جواب بده یک سری پارامتر واسه اون گذاشتم تا کاربر بنا به استفاده خودش اونا رو ست کنه و سرعت یکم بیشتر بشه. البته شما در main این کلاس یک نمونه استفاده از این متد رو می بینید. می تونید متد رو تو هرجا که دوست دارید کپی کنید و از اون استفاده کنید.


import java.util.Arrays;
import java.util.regex.Pattern;
import java.nio.charset.Charset;
import java.nio.charset.CharacterCodingException;
import java.nio.ByteBuffer;
import java.io.FileInputStream;
import java.io.File;
import java.io.IOException;

public class CharsetDetector {

/**
* Detecting automatically charset name of a string by finding a pattern
* within first maxLengthArray characters of the string.
*
* @param stringByteArray Byte array of string to find charset name of it.
* @param regexPattern Regular expression pattern that be
* in first maxLengthArray characters of
* the string to recognize charset validity.
* @param maxLengthArray Maximum length of stringByteArray that be used for
* testing regexPattern in first it characters of the string.
* @return return charset name of stringByteArray. return null when can not find it.
*/
public static String charsetDetector(byte[] stringByteArray, String regexPattern, int maxLengthArray) {
final String[] STANDARD_CHARSETS_NAME = {
"UTF-8", "ISO-8859-1", "windows-1256", "windows-1254", "windows-1250", "windows-1252", "US-ASCII",
"UTF-16", "UTF-16LE", "UTF-16BE", "UTF-32", "UTF-32LE", "UTF-32BE", "IBM862", "IBM866", "IBM850",
"IBM852", "IBM775", "IBM855", "IBM437", "IBM00858", "IBM857", "KOI8-R", "KOI8-U", "ISO-8859-2",
"ISO-8859-4", "ISO-8859-5", "ISO-8859-7", "ISO-8859-9", "ISO-8859-13", "ISO-8859-15", "windows-1251",
"windows-1253", "windows-1257", "x-UTF-16LE-BOM", "X-UTF-32LE-BOM", "X-UTF-32BE-BOM", "x-IBM874", "x-IBM737"
};

byte[] byteArray = null;
if (stringByteArray.length > maxLengthArray) {
/** saving sub byte array of stringByteArray in byteArray for increase Performance */
byteArray = Arrays.copyOfRange(stringByteArray, 0, maxLengthArray);
} else {
byteArray = Arrays.copyOf(stringByteArray, stringByteArray.length);
}

Charset charset = null;
String decodedDocument = "";
for (int counter = 0; counter < 39; counter++) { // 39 ===> Length of STANDARD_CHARSETS_NAME
charset = Charset.forName(STANDARD_CHARSETS_NAME[counter]);

try {
/** Decoding byteArray */
decodedDocument = charset.newDecoder().decode(ByteBuffer.wrap(byteAr ray)).toString().trim();
} catch (CharacterCodingException e) {
/** when this happend, it means charset is invalid and
* must be continued for next charset */
continue;
}

if (Pattern.compile(regexPattern, Pattern.CASE_INSENSITIVE).matcher(decodedDocument) .find()) {
return STANDARD_CHARSETS_NAME[counter].trim();
}
}

/** when this happend, it means charset name not found */
return null;
}

public static void main(String[] args) {
try {
// For example : Getting string of html file.
FileInputStream stream = new FileInputStream(new File("Path of your file"));
byte[] streamBytes = new byte[stream.available()];
stream.read(streamBytes);

String charsetName = charsetDetector(streamBytes, "<\\s*html", 800);
String result = Charset.forName(charsetName).newDecoder().decode(B yteBuffer.wrap(streamBytes)).toString().trim();
System.out.println("result =\n" + result);
} catch (IOException e) {
e.printStackTrace();
}

// Other charset tools
/*
// Find html charset
BufferedReader reader = new BufferedReader(new InputStreamReader(content));
int charsetCode = reader.read();
switch (charsetCode) {
case 65533: {
document = new HtmlDocument(content, "UTF-16");
}
break;
case 65279: {
document = new HtmlDocument(content, "UTF-16LE");
}
break;
case 60: {
document = new HtmlDocument(content);
}
break;
}
*/

/*
// Convert a string to another string with charset different
Charset charset = Charset.forName("ISO-8859-1");
CharsetEncoder encoder = charset.newEncoder();

charset = Charset.forName("UTF-8");
CharsetDecoder decoder = charset.newDecoder();

try {
ByteBuffer bbuf = encoder.encode(CharBuffer.wrap("a string"));
CharBuffer cbuf = decoder.decode(bbuf);
String s = cbuf.toString();
} catch (CharacterCodingException e) {
// Do anything
}
*/

/*
// Convert a string to another string with charset different via file
HtmlDocument document = new HtmlDocument(content, "UTF-16");
if (!Pattern.compile("<\\s*html").matcher(document.getDocument()).find()) {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File("Temp.txt")), "UTF-16"));
writer.write(document.getDocument());
writer.close();

document = new HtmlDocument(new FileInputStream(new File("Temp.txt")), "UTF-16LE");
}
*/
}
} //End


در زیر این کلاس روش های دیگری رو گذاشتم گفتم شاید تو یک جا به دردتون بخوره و ازتون وقت نگیره.

۳. من از راه دوم استفاده می کردم تا اینکه بالاخره یک jar فایل پیدا کردم که درست کار می کرد. خودم الان از این راه استفاده می کنم و تا حالا به مشکل برنخوردم. یک نمونه مثال از طرز استفاده از این کلاس ها در زیر گذاشتم.


// stream is a inputstream
byte[] streamBytes = new byte[stream.available()];
stream.read(streamBytes);

CharsetDetector detector = new CharsetDetector();
result = detector.setText(streamBytes).detect().getString() .trim();


لینک jar فایل مربوطه ضمیمه شده. تعداد partها ۱۰ تا هست ولی به دلیل محدودیت ۲بار میفرستم. اولی رو extract بکنی بقیه هم دنبالش می ره.

نمی دونم که چقدر واسه اونا که این مطلب رو می خونند مفید بوده. ازتون خواهش می کنم که اگر خوندید و به دردتون خورد واسم یک پاسخ بذارید یا اگر شما هم تجربه ای دارید اونو یا لینکش رو همین جا بذارید تا دیگران هم استفاده کنند.
این جوری بیشتر احساس مفید بودن می کنم.
شاید اینجوری بیشتر تشویق بشیم و بریم به سمت اینکه مثل بقیه دنیا تجربیاتمون رو در اختیار همدیگه قرار بدیم و سرعت بیشتری تو پیشرفت خودمون و در نتیجه اجتماعمون داشته باشیم.
بیایید با تلاش بیشتر و update بودن نترسیم از این که یکی دیگه چیزی رو که بلدیم یاد بگیره چون در غیر این صورت مثل اجدادمون رفتار کردیم و باعث عقب موندگیمون شدیم. اینجوری در آینده هم پول رو داریم هم یک اجتماع ثروتمند رو.

Vesal64
سه شنبه 08 بهمن 1387, 20:51 عصر
این هم بقیه تکه های فایل مورد نظر.
همه را در یک جا کپی کرده و اولی رو exract کنید.