Парсин текстового файла
От: svsanek  
Дата: 29.08.08 12:28
Оценка:
Доброе всем время суток. Есть задача:
Исходные данные:
Входной поток — набор слов. Для простоты предполагается, что данные хранятся в текстовом файле, но при этом общее количество слов и размер файла заранее неизвестны, т.е. нельзя прочитать в память весь файл целиком. Кодировка — Задается.
Необходимо выполнить разбора входного текста на слова и вычислить частоту встречаемости каждого слова. В качестве "слова" понимается набор символов, состоящий из букв, цифр и символа подчеркивания.
Все остальные символы считаются разделителями.
При проектировании следует исходить из предположения, что создаваемый код будет использоваться в рамках реальной системы.
Требования: расширяемость, производительность, экономия памяти
Результат:
Вывести в текстовый файл список слов со значениями частоты встречаемости.
Должна быть предусмотрена возможность вывода списка, отсортированного по частоте.
Сортировка по словам не требуется.
Язык реализации: Java.
Есть вот такая реализация этой задачи:
Основной класс
package parser;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.Properties;
/**
 * 
 * @author Alexander
 * Main Class
 *
 */
public class Parser {

    private static String inputFilePath;

    private static String outputFilePath;

    private static String encoding;

    /**
     * @param args
     */
    public static void main(String[] args) {
        InputStream is = Object.class.getResourceAsStream("/regexp.properties");
        Properties props = new Properties();
        try {
            //load properties
            props.load(is);
            String regexpString = props.getProperty("regexp");
            TextParser.setRegexp(regexpString);
            String maxBuffSize = props.getProperty("maxBufferSize");
            TextParser.setMAX_BUFF_SIZE(Integer.parseInt(maxBuffSize));
            inputFilePath = props.getProperty("inputFilePath");
            outputFilePath = props.getProperty("outPutFilePath");
            encoding = props.getProperty("encoding");
        } catch (IOException e) {
            e.printStackTrace();
            System.err.println("no properties");
            System.exit(666);
        }
        BufferedReader breader;
        try {
            System.out.println("start work");
            //open file with name=inputFileName and with encoding=encoding
            breader = new BufferedReader(new InputStreamReader(
                    new FileInputStream(inputFilePath), encoding));
            TextParser.textParsing(breader);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(outputFilePath), encoding));
            ParserUtil.GenerateReport(writer);
            System.out.println("complete work");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }

    }

}

Он собственно загружает проперти и открывает потоки.
Есть класс утиль, в котором содержатся утилитарные методы

package parser;

import java.io.BufferedWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;


/**
 * 
 * @author Alexander
 * Class with utilits methods
 */
public class ParserUtil {

    //Map for storing lexems: String - lexem, Integer - count
    static HashMap<String, Integer> countsOfWords = new HashMap<String, Integer>();

    //sortin map by value
    private static List SortMap(HashMap<String, Integer> map) {
        List entryList = new ArrayList(map.entrySet());
        Collections.sort(entryList, new ValuesComparator());
        return entryList;
    }

    //method for adding lexem to the map
    public static void AddWordToHashMap(String newWord) {
    
        if (countsOfWords.containsKey(newWord)) {
            Integer count = countsOfWords.get(newWord);
            count++;
            countsOfWords.put(newWord, count);
        } else {
            Integer count = 1;
            countsOfWords.put(newWord, count);
        }
    }

    //write result into the file
    public static void GenerateReport(BufferedWriter writer) throws IOException {
        List entryList = ParserUtil.SortMap(countsOfWords);
        Entry<String, Integer> entry;
        for (Iterator itr = entryList.iterator(); itr.hasNext();) {
            entry = (Entry<String, Integer>) itr.next();
            writer.write(entry.getKey() + "=" + entry.getValue() + " ");
        }
        writer.close();

    }

}

Класс в котором производится парсинг текста.

package parser;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * 
 * @author Alexander
 * Class for text parsing
 *
 */
public class TextParser {
    private static int MAX_BUFF_SIZE;

    private static String regexp;

    private static boolean partFlag;

    private static String completeString;

    /**
     * This method load data from txt file into the buffer and use
     * java.util.regex.Matcher, and java.util.regex.Pattern for finding lexems
     * 
     * @param breader -
     *            buffered reader
     * @throws IOException
     */
    public static void textParsing(BufferedReader breader) throws IOException {
        // compile regular expresion
        Pattern lexem = Pattern.compile(regexp);
        int bufferCount;
        // word - founded lexem
        String word = new String();
        // part of lexem
        String tmpString = new String();
        char[] charBuffer = new char[MAX_BUFF_SIZE];
        partFlag = false;
        // reads chars from file into the buffer
        // bufferCount - count of chars wich we had read
        while ((bufferCount = breader.read(charBuffer)) != -1) {
            // create new string
            String str = new String(charBuffer, 0, bufferCount);
            // use matcher for finding lexems
            Matcher mat = lexem.matcher(str);
            while (mat.find()) {
                // find lexem
                word = mat.group();
                // if lexem < then our buffer and there is no lexem's part in
                // buffer
                if ((mat.end() < MAX_BUFF_SIZE) && !partFlag) {
                    // we founded lexem
                    completeString = mat.group();
                } else {
                    // find secod part of the lexem
                    if ((mat.start() == 0) && partFlag
                            && (mat.end() != MAX_BUFF_SIZE)) {
                        completeString = tmpString + mat.group();
                        partFlag = false;
                    } else {
                        // if second part > then our buffer
                        if ((mat.start() == 0) && partFlag
                                && (mat.end() == MAX_BUFF_SIZE)) {
                            String secondPart = new String(tmpString);
                            tmpString = secondPart + mat.group();
                            partFlag = true;
                        } else {
                            // if lexem > then our buffer
                            if ((mat.end() == MAX_BUFF_SIZE)) {
                                // set flag
                                partFlag = true;
                                // store part of the string
                                tmpString = word;
                            } else {
                                completeString = tmpString;
                                partFlag = false;
                            }
                        }

                    }
                }
                if (!partFlag) {
                    ParserUtil.AddWordToHashMap(completeString);
                }
            }
        }
        breader.close();
    }

    public static void setMAX_BUFF_SIZE(int max_buff_size) {
        MAX_BUFF_SIZE = max_buff_size;
    }

    public static void setRegexp(String regexp) {
        TextParser.regexp = regexp;
    }
}

И последний класс — который позволяет сортировать мэп по валуе

package parser;

import java.util.Comparator;
import java.util.*;

/**
 * 
 * @author Alexander
 * Class for compare values from hash map
 *
 */

public class ValuesComparator implements Comparator {

    public int compare(Object arg0, Object arg1) {
        Map.Entry first = (Map.Entry)arg0;
        Map.Entry second = (Map.Entry)arg1;
        Comparable comparableFirst = (Comparable)first.getValue();
        Comparable comparableSecond = (Comparable)second.getValue();        
        return comparableFirst.compareTo(comparableSecond);
    }

}

И наконец — файл с пропертис

regexp=[\\w+[\\p{L}+[\\d+]]]+
inputFilePath=D:\\Eclipse\\Test\\1.txt
outPutFilePath=rezult.txt
maxBufferSize=10
encoding=KOI8-R


Эта реализация работает. Все парсит. Подскажите пожалуйста — как в этой реализации повысить производительность? Основные требования — "Требования: расширяемость, производительность, экономия памяти". Как эти параметры соблюсти? может есть какие-нибудь приемы или паттерны для похожих задач?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.