410013796724260
• Webmoney
R335386147728
Z369087728698
Анализ текста, StringTokenizerКласс StringTokenizer пакета java.util предназначен для разложения строки на составляющие. Под токенацией понимается процесс разделения последовательности строки на части. Будучи удобным в использовании, StringTokenizer имеет серьезные функциональные ограничения. Так StringTokenizer раскладывает входную строку на части согласно переданных ему списка разделителей. Он не выполняет проверку на наличие разделителя внутри подстроки и не возвращает пустую строку нулевой длины, если во входном потоке обнаружена последовательность разделителей. Конструкторы класса StringTokenizerДля создания экземпляра StringTokenizer можно использовать один из следующих конструкторов:
Если строка "str" неопределена, т.е. равна null, то вызывается исключение NullPointerException. Пример использования класса StringTokenizer
String s;
s = "Тестовая строка, используемая для разложения на слова";
StringTokenizer st = new StringTokenizer(s, " \t\n\r,.");
while (st.hasMoreTokens()) {
// Выводим лексемы в консоль
System.out.println(st.nextToken());
}
Методы класса StringTokenizer, countTokens, hasMoreTokens, nextToken
Особенности использования класса StringTokenizerПервый конструктор с одним параметром str не выполняет проверку наличия в строке подстроки. Поэтому строка "Привет. Завтра \"21 сентября \" мы идем в театр." разбивается на следующие части: [Привет., Завтра, "21, сентября, ", мы, идем, в, театр.] // вместо [Привет., Завтра, "21 сентября " , мы, идем, в, театр.] Второй конструктор не отслеживает последовательное появление разделителя во входном потоке. Поэтому если строку "book, author, publication,,,date published" разложить на части, используя в качестве разделителя символ запятой ",", то получим набор из 4-x слов book, author, publication, date published вместо шести значений book, author, publication, "", "", date published , где "" означает строку нулевой длины. Чтобы получить все шесть частей необходимо использовать третий конструктор и установить параметр returnDelims в true. Особенность установки параметра returnDelims в true, является очень важной. Особенно когда текстовые данные поступают динамически и их необходимо раскладывать на составляющие и записывать в базу данных. В этом случае необходимо получить значения для всех полей таблицы. Третий конструктор не будет работать также и в том случае, когда информационная часть строки соответствует разделителю и находится внутри подстроки. Так, например после токенации следующей строки : "book, author, publication,\",\",date published" мы получим шесть частей book, author, publication, ", ", date published вместо пяти book, author, publication, ',', date published. В этом случае использование третьего конструктора с установленным в true значением returnDelims также не поможет. Адаптивный токенайзер, CustomTokenizerСоздать свой токенайзер на все случаи жизни - дело очень затратное по временным ресурсам, и не очень благодарное. Можно получить очень сложный код, бизнес-логика которого в скором времени забудется, и внесение дополнительных изменений потребует серьезных усилий. Ниже предложен подход решения одной из рассмотренных выше проблем - как исключить из анализа/разложения текст, обрамленный кавычками (двойными, одинарными) или разного рода скобками. Решение проблемы простое. Необходимо в токенайзер передать модифицированную строку для анализа, где проблемные участки текста заменены заглушками. А при извлечении токенов, вместо заглушек вернуть их исходное значение. То есть текст предварительно, перед передачей токенайзеру для разложения, обрабатывается и значение токена восстанавливается, перед возвращением. Листинг настраиваемого токенайзера :
import java.util.Map;
import java.util.HashMap;
import java.util.StringTokenizer;
public class CustomTokenizer
{
private StringTokenizer tokenizer = null;
private int tokenNum = 0;
private int totalTokens = 0;
private final String QUOTE = "\"";
private Map<String, String> substitutes;
// шаблон заглушки
private final String SUBSTITUTE =
"__SUBSTITUTE__";
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Конструктор
* @param text текстовая строка
* @param delim строка разделителей
*/
public CustomTokenizer(String text, String delim)
{
substitutes = new HashMap <String, String>();
tokenizer = new StringTokenizer(setSubstitute(text),
delim, true);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Конструктор
* @param text текстовая строка
* @param delim строка разделителей
* @param includeDelim флаг включения разделителей
* как токенов
*/
public CustomTokenizer(String str, String delim,
boolean includeDelim)
{
tokenizer = new StringTokenizer(setSubstitute(str),
delim, includeDelim);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Функция замены "проблемного" текста в кавычках
* заглушками. Проблемный текст в строке, выделенный
* двойными кавычками, заменяется
* @param text исходный текст
* @return измененный текст
*/
private String setSubstitute(final String text)
{
String temp = text;
int id = 0;
// Определение начала и конца проблемного кода
int startQuote = temp.indexOf(QUOTE, 0);
int endQuote = -1;
if (startQuote >= 0 )
endQuote = temp.indexOf(QUOTE, startQuote + 1);
// Цикл перебора текста
while (((startQuote >= 0) &&
(endQuote > startQuote))) {
// Извлечение проблемного текста
String txt;
txt = temp.substring(startQuote, endQuote + 1);
// Определение ключа
String key = SUBSTITUTE + String.valueOf(id++);
// Замена проблемного текста заглушкой
temp = temp.replaceFirst(txt, key);
// Сохранение проблемного текста с ключом
substitutes.put(key, txt);
// Подготовка к следующему циклу
startQuote = temp.indexOf(QUOTE, 0);
if (startQuote >= 0)
endQuote = temp.indexOf(QUOTE,startQuote+1);
}
return temp;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Функция возвращения следующего токена строки
* @return следующий токен
*/
public String nextToken()
{
String sToken = tokenizer.nextToken();
if (substitutes.containsKey(sToken.trim()))
sToken = substitutes.get(sToken.trim());
tokenNum++;
return sToken;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Функция проверки наличия оставшихся токенов
* @return логическое значение true, если имеется
* еще токен
*/
public boolean hasMoreTokens()
{
if (totalTokens == 0)
totalTokens = countTokens();
return (tokenNum < totalTokens);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Функция проверки наличия оставшихся токенов
* @return логическое значение true, если имеется
* еще токен
*/
public boolean hasMoreElements()
{
return hasMoreTokens();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Функция получения следующего токена
* @return текущий токен строки типа Object
*/
public Object nextElement()
{
return nextToken();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* Функция определения количества токенов в строке
* @return количество токенов
*/
public int countTokens()
{
return tokenizer.countTokens();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public static void main(String[] args)
{
String string;
// string = "hi, hello,, \"how, are, qrt, u\", good, "
// + "\"fine, hty, great\", data";
// string = "hi, how, \"are, u\", hello, \"how, are\", u";
string = "Привет. Завтра \"21 сентября \" "
+ "мы идем в театр.";
System.out.println("~~~ Исходная строка ~~~\n"
+ string);
CustomTokenizer tokenizer;
tokenizer = new CustomTokenizer(string, " .", false);
System.out.println("\nколичество токенов = " +
tokenizer.countTokens());
System.out.println("\n~~~ Список токенов ~~~");
int i = 0;
while(tokenizer.hasMoreTokens())
System.out.println("" + ++i + " = " +
tokenizer.nextToken());
}
}
В данном токенайзере имеется две функции, код которых можно модифицировать под разные случаи жизни:
Результат выполнения программы выведет в консоль следующую информацию : ~~~ Исходная строка ~~~ Привет. Завтра "21 сентября " мы идем в театр. количество токенов = 7 ~~~ Список токенов ~~~ 1 = Привет 2 = Завтра 3 = "21 сентября " 4 = мы 5 = идем 6 = в 7 = театр |
