Настройки форм
Права доступа
Ролевой механизм
Загрузка модулей410013796724260
Анализ текста, 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 = театр |
