Пока собираюсь с мыслями по поводу написания одной большой статьи про использование Ribbon Controls решил между делом поразбираться с различными API.
Но прежде, чем предоставлю модуль для работы с API, спрошу Вас вот что.
Суть проблемы такова: есть 3 компьютера – 2 стационара и 1 ноутбук. На стационарах стоят винды XP (SP3, все обновления совпадают), на ноуте – стоит винда XP SP-2 и Ubuntu 9.10. Стационары подключены к Интернету через одного и того же провайдера. На первом стационаре не грузятся все страницы вида http://code.googele/… На втором стационаре от Гуглы работает только поиск.Подключаю к инету ноутбук, запускаю Windows, открываю Гугл – работает всё кроме переводчика и FeedBurner’а. Под Ubuntu – работает все.
Вопрос: что за фигня происходит? ' '
Пробую разобраться уже с неделю, попеременял все браузеры, какие только есть в природе, чистил кэши, куки. Пересоздавал подключение, причём не только к инету, но и менял IP-адрес для локалки, через которую выхожу в Инет. Сегодня переставил сетевуху на одном из стационаров – нихрена. На ноуте сносил винду – тоже не помогло. Такое ощущение, что в винде млять чёрная дыра в которую Гулу засасывает. Если кто в курсе в чём проблема – подскажите плз, так как очень неудобно сидеть за двумя компами и перетыкать туда-сюда сетевой кабель :)
Ну, а теперь преступиим к главному – API Яндекс.Спеллера.
Во-первых, следует объяснить тем, кто не в курсе, что это за API.
Яндекс.Спеллер – это сервис проверки правописания, который помогает находить и исправлять орфографические ошибки. Работа сервиса основана на использовании орфографических словарей для трех языков – русского, украинского и английского.
В принципе, для тех, кто большую часть времени работает в офф-лайне этот сервис особо не пригодиться. Другое дело – использовать его в своих он-лайн проектах и программах, ориентированных на работу в Сети.
В целом, работа с API Яндекса никогда не вызывали, по крайней мере у меня, особых осложнений. В основном вся работа основывается на работе с двумя-тремя методами, у которых пара-тройка входных параметров. Самое “сложное” – это правильно разобрать ответ сервера.
Судя по тому, что написано в документации к Яндекс.Спеллеру, для нас наиболее важно научиться использовать метод checkText.. Его мы сегодня и рассмотрим.
Метод checkText Яндекс.Спеллера
Метод проверяет орфографию в указанном отрывке текста. Для использования метода допустимо использовать как GET так и POST запросы. При этом размер передаваемого текста в POST-запросе не должен превышать 10000 символов.
Чтобы лишний раз не копипастить документацию я просто приведу ссылку на описание метода. Судя по тому, что сказано в документации, наша работа с сервисом будет состоять из двух частей:
- Отправка POST-запроса с текстом для проверки
- Получение ответа и парсинг XML.
Для работы нам понадобиться совсем немного модулей: SysUtils, Classes, XMLIntf,xmldom, XMLDoc;
Ну и для отправки запросов я использовал httpsend из библиотеки synapce. Вы, если хотите, можете использовать тот же IdHTTP из Indy.
Первое, что делаем – это объявляем все константы, которые могут потребоваться нам для работы, а именно:
- Коды ошибок Яндекс.Спеллера
- Константы настроек Яндекс.Спеллера
- Ну и, чтобы вообще было хорошо – создадим несколько ресурсных строк для описания ошибок
У меня получилось следующее:
resourcestring rcERROR_TEXT_LENGTH = 'Общая длина передаваемого текста превышает 10000 символов!'; rcERROR_UNKNOWN_WORD = 'Слова нет в словаре'; rcERROR_REPEAT_WORD = 'Повтор слова'; rcERROR_CAPITALIZATION = 'Неверное употребление прописных и строчных букв'; rcERROR_TOO_MANY_ERRORS = 'Текст содержит слишком много ошибок'; const IGNORE_UPPERCASE = 1; IGNORE_DIGITS = 2; IGNORE_URLS = 4; FIND_REPEAT_WORDS = 8; IGNORE_LATIN = 16; NO_SUGGEST = 32; FLAG_LATIN = 128; ERROR_UNKNOWN_WORD = 1; ERROR_REPEAT_WORD = 2; ERROR_CAPITALIZATION = 3; ERROR_TOO_MANY_ERRORS = 4; |
Теперь договоримся как будем хранить сообщения об орфографических ошибках. Чтобы все было точно как задумано в сервисе, будем хранить всю информацию об ошибке как есть. Для этого вводим новый тип данных:
type TBadWord = record Word: string;//слово с ошибкой ErrCode: integer;//код ошибки ErrMsg : string;//описание ошибки Pos:integer;//позиция слова с ошибкой (отсчет от 0); Row:integer;//номер строки (отсчет от 0) Col:integer;//номер столбца (отсчет от 0); Len:integer;//длина слова с ошибкой Variants: TStringList; //варианты правильного написания end; |
И ещё пару типов
type TBadWords = array of TBadWord; type TTextFormat = (tfPlain, tfHTML); |
Теперь мжно отправлять данные на сервер и анализировать ответ. Для этого я создал такую функцию:
function CheckGrammar(const aText:string; Options:integer=0;lang:string='ru,en';format:TTextFormat=tfPlain):TBadWords; implementation function CheckGrammar(const aText:string; Options:integer;lang:string;format:TTextFormat):TBadWords; var Query: TStringStream; Doc: IXMLDocument; List,Variant: IDOMNodeList; i,j:integer; begin try Query:=TStringStream.Create(''); Query.WriteString('text='+aText+'?='+lang+'&options='+inttostr(Options)); case format of tfPlain: Query.WriteString('&format=plain&ie=1251'); tfHTML: Query.WriteString('&format=html&ie=1251'); end; if Length(Query.DataString)>10000 then raise Exception.Create(rcERROR_TEXT_LENGTH); with THTTPSend.Create do begin Document.LoadFromStream(Query); MimeType:='application/x-www-form-urlencoded'; if HTTPMethod('POST','http://speller.yandex.net/services/spellservice/checkText') then begin Doc:=NewXMLDocument(); Doc.LoadFromStream(Document); List:=Doc.DOMDocument.getElementsByTagName('error');//получаем список ошибок SetLength(Result,List.Length);//устанавливаем длину массива for i:=0 to List.length-1 do begin //запоминаем атрибуты ошибки with List.item[i] do begin Result[i].ErrCode:=StrToInt(attributes.getNamedItem('code').nodeValue); Result[i].Pos:=StrToInt(attributes.getNamedItem('pos').nodeValue); Result[i].Row:=StrToInt(attributes.getNamedItem('row').nodeValue); Result[i].Col:=StrToInt(attributes.getNamedItem('col').nodeValue); Result[i].Len:=StrToInt(attributes.getNamedItem('len').nodeValue); end; case Result[i].ErrCode of ERROR_UNKNOWN_WORD:Result[i].ErrMsg:=rcERROR_UNKNOWN_WORD; ERROR_REPEAT_WORD:Result[i].ErrMsg:=rcERROR_REPEAT_WORD; ERROR_CAPITALIZATION:Result[i].ErrMsg:=rcERROR_CAPITALIZATION; ERROR_TOO_MANY_ERRORS:Result[i].ErrMsg:=rcERROR_TOO_MANY_ERRORS; end; //читаем дочерние элементы Variant:=List.item[i].childNodes; Result[i].Word:=(List.item[i].firstChild as IDOMNodeEx).text; Result[i].Variants:=TStringList.Create; for j:=1 to Variant.length-1 do //оставшиеся дочерние узлы - варианты Result[i].Variants.Add((Variant.item[j]as IDOMNodeEx).text); end; end; end; finally FreeAndNil(Query); end; end; |
Разберемся, что здсь происходит. Вначале создается тело нашего POST-запроса в зависимости от входных параметров. При этом, обратите внимание на последний необязательный параметр: ie=1251. Можно было бы обойтись и без него, но для этого необходимо переводить наш параметр aText в кодировку utf-8.
Далее проводится проверка длины текста в теле запроса. Если длина превышает 10000 символов, то работа функции завершается, иначе переходим к следующему шагу – отправке запроса.
MimeType:='application/x-www-form-urlencoded'; |
Определяет заголовок (Headers) Content-Type. Если не использовать заголовок или использовать другое его значение – сервис вернет нам ошибку “Unrecognized Content Type … “. Отправляем запрос и анализируем XML-документ.
Анализ как таковой проводится элементарно:
- Получаем список всех узлов error – размер списка и будет размером массива, который возвращает функция
- Далее проходим по порядку по каждому из узлов списка (цикл по i) и читаем все атрибуты попутно занося в элемент массива описание ошибки в зависимости от значения атрибута code.
- Получаем для каждого узла List.item[i] список дочерних узлов.
- Исходя из описания API первым дочерним узлом всегда является слово с ошибкой – читаем первый дочерний узел и заносим его значение в поле Word
- Остальные дочерние узлы (если они имеются) – это варианты правильного написания слова. Создаем цикл по j и читаем значения оставшихся узлов.
Вот и все. Остается продемонстрировать работу функции на примере. Использовать можно, например так:
CheckGrammar('синхрафазатрон в дубне', 5); |
При этом приверка будет проходить с использованием опций: IGNORE_UPPERCASE и IGNORE_URLS.
Можно вызвать метод и так:
CheckGrammar('синхрафазатрон в дубне', IGNORE_UPPERCASE+ IGNORE_URLS, 'ru'); |
Так будет проверяться только русский текст, опять же используя опции из предыдущего примера.
Вот пажалуй и все :) Готовый модуль, рассмотренный в этом посте + пример его использования можно скачать здесь.
Если не знаете, что почитать - посмотрите рецензии на книги по интересующему Вас жанру или автору - так будет проще определиться с ответом на вопрос "Что почитать" ;)
Сегодня купить паркет в Санкт-Петербург стало ещё проще - заходите на pret-a-parquet.ru, выбираете и дело в шляпе.
Интернет - это такая большая штука где можно за минуту узнать не только какая погода в Риме сегодня, но и прочитать отзывы о Пекине, заказать путёвку и даже купить настоящую (не электронную) книгу. Что же нас ждёт в будущем? :)
----------------------------
Related posts:










17 Jan 2010 в 12:39 am
[...] This post was mentioned on Twitter by progg, Vlad and ru_webdev, monitorium. monitorium said: API Яндекс.Спеллера в Delphi. | Delphi в Internet: Встраиваем он-лайн проверку орфографии в наше прилож… http://bit.ly/5v7se6 /*progg.ru [...]
20 Jan 2010 в 10:26 am
Получается, что я Вас проэкслуатировал.
Я сам пытался решить эту задачу, залез в поисках решения на этот блог.
Сообщил, что эта задача мне интересна.
И вот оно решение!
Спасибо огромное!
У меня всего час в неделю на программирование, и узучить XML на практике не успеваю.
Ещё раз спасибо.
С уважением, Гимаев Наиль.
20 Jan 2010 в 11:53 am
:) Да как бы эксплуатации никакой не было – просто решил узнать, что Вас так заинтересовало в Яндекс.Спеллере. А прятать за пазухой решение и потом продавать – не в моих целях и планах. Пользуйтесь на здоровье. Будут проблемы с работой модуля – говорите – будем исправлять
23 Jan 2010 в 7:32 pm
А для Spell-checker-a Гугла решение, случайно, не планируется? ;-)
Всё-таки Гугл поддерживает намного больше языков.
23 Jan 2010 в 9:11 pm
Для этого не нужно быть гуглом.
Возможно в ближайшее время появится подражатель яндекса, который сделает сайт с поддержкой этого API. Прикрутит к нему HSpell (самый популярный на данный момент). Словари для всех языков можно скачать с сайта OpenOffice. Тогда все смогут пользоваться проверкой текстов на всех языках. Для профессионального веб-программиста работа на один день.
24 Jan 2010 в 3:08 am
Гимаев Наиль, спасибо за идею! Мне вдруг пришло в голову, что тогда проще использовать этот Spellchecker напрямую. =)
24 Jan 2010 в 6:24 pm
Алексей, я сейчас, признаться, вообще мало чего планирую, кроме работы на 2х работах :) Но ежели дадите ссылочку на API от Гугла, то в свободное от работы время (думаю скоро оно появится) поковыряюсь с их чекером…тем более, что в последнее время меня частенько пробивает поковыряться во всяких API
24 Jan 2010 в 7:42 pm
Я погорячился. Api для Spellchecker-a гугла не опубликовано официально и не документировано.
24 Jan 2010 в 7:48 pm
А неофициальная версия есть?)
24 Jan 2010 в 8:42 pm
Есть, конечно. Народ расковырял Google Toolbar, чтобы посмотреть как там реализована проверка правописания. =) Но толку-то? На такое решение нельзя полагаться – если протокол неофициальный, то он может быть изменён в любой момент. Даже GoogleChrome использует для проверки правописания не сервисы гугла, а вышеупомянутый hunspell.
Но если очень хочется поковыряться с API – то, вот идея. Для Google API ещё нет полной бесплатной библиотеки для Delphi. Есть решения и примеры для работы с отдельными сервисами, в основном через публичные методы. А полного API c авторизацией и поддержкой всех методов нет. С другой стороны, раз нет, значит никому и не нужно. =)
24 Jan 2010 в 8:51 pm
Ну на полное API Google как бэ действительно всем пофег, т.к. есть куча “прибамбасов”, которые в программах на Delphi будут выглядеть как у собаки пятая лапа, например. А так, что-то вздумалось спаять на досуге Яндекс.Спеллер+Google.Translate…ну и ещё чё-нить до кучи :)
Посмотрел по ссылке пост…что-то мне этот чеккер очень сильно напомнил Спеллер :) Ждем поддержки тучи языков от Яндекса…
25 Jan 2010 в 12:58 am
Совсем полный – да, пофиг. Мне, например, пофиг APIAdsense, AdWords, Analytics, Apps и многие другие. А интересны Calendar API (или любой способ для работы с Google Tasks), Translate API, Google Static Maps API.
Google Calendar API, наверняка потребует реализовать Google Account Authentication и Google Data Protocol, а имея удобные базовые классы – по идее можно будет легко прикрутить и поддержку других сервисов. Но это так… мысли вслух. =)
25 Jan 2010 в 12:24 pm
Никогда не задумывался, но AdWords – хороший способ превратить бесплатную но популярную программу в приносящую доход. Нужно только подключить рекламу от гугла к своей программе, и тогда популярность можно будет вернуть деньгами.