root/ConcordanceKWIC.cpp

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. generate

   1 /* -*- coding: utf-8; mode: c++; -*-
   2  * Concordance to A. S. Pushkin's Works - KWIC generation
   3  * $Id: ConcordanceKWIC.cpp 47 2014-06-04 17:03:50Z isao $
   4  * Copyright (C) 2012, isao yasuda
   5  */
   6 
   7 #include "Concordance.hpp"
   8 
   9 using namespace Wt;
  10 using namespace boost::interprocess;
  11 
  12 // 共有メモリオブジェクト
  13 extern managed_shared_memory segment1; // Corpus, TitleDB
  14 extern managed_shared_memory segment2; // Word Tree
  15 extern managed_shared_memory segment3; // work
  16 
  17 // 共有メモリリソースアドレス
  18 extern shmmap_type* corpus_map;      // Corpus map アドレス
  19 extern shmmap_type* tdb_map;         // TitleDB アドレス
  20 extern offset_ptr<tree> word_tree_l; // Word Tree Lemmatized form アドレス
  21 extern offset_ptr<tree> word_tree_a; // Word Tree Appearance form アドレス
  22 
  23 // 近接隣接距離 MAX 値
  24 extern int MAXDIST;
  25 
  26 // リンクリソース
  27 static const std::string URLbase = "/pushkin/web/";
  28 
  29 // コンコーダンス生成
  30 void Concordance::generate()
  31 {
  32     boost::timer t;             // 処理時間タイマ
  33     std::stringstream ss;       // 数値変換用ストリングストリーム
  34 
  35     // ユーザ入力単語式
  36     std::string ldata = (expEdit->text()).toUTF8(); // 元入力
  37     std::string userip = "IP: " + ipadr + " Req: " + ldata;
  38     logging(userip.c_str(), INFO);
  39 
  40     // 大文字変換
  41     std::string udata = boost::locale::to_upper(ldata);
  42 
  43     // 実行 Word Tree の選択,Lemmatizer 実行可否判断
  44     offset_ptr<tree> word_tree;      // 実行 Word Tree
  45     WString opts(ldata, UTF8);
  46     opts = L" (Ваш ввод: " + opts;
  47     // Lem Tree on なら見出語形ツリー選択
  48     if (wbg0->checkedId() == 0) {
  49         word_tree = word_tree_l;     // select Lemmatized
  50         opts += L"; DB: Lemmatized; Лемматизация ввода: ON)";
  51     } else {
  52         // off なら出現形ツリー選択
  53         word_tree = word_tree_a;     // select Non Lemmatized
  54         opts += L"; DB: Non Lemmatized; Лемматизация входа: OFF)";
  55     }
  56 
  57     // ユーザ入力をトークナイザで分解し,式を vector にセット
  58     std::vector<std::string> wds;
  59     exp_tokenizer(udata, wds);
  60     if (wds.empty()) {
  61         errorsend("No expressions specified.");
  62         return;
  63     }
  64 
  65     // 式のチェック
  66     std::vector<query> qrv; // クエリ構造体の vector
  67     for (std::vector<std::string>::iterator wi = wds.begin();
  68             wi != wds.end(); wi++) {
  69         // クエリをチェックし,演算種別/オペランドをセットした vector を作成し,rc 判別
  70         int r = checkquery(*wi, genrev, qrv);
  71         switch (r) {
  72         case 1: {// 記号だけの文字条件エラー
  73             escapetag(*wi);
  74             errorsend("Regular expression has no normal charcters: " + *wi);
  75             return;
  76         }
  77         case 2: {// ジャンル文字条件エラー
  78             escapetag(*wi);
  79             errorsend("On genre condition more than 7 genres expression must have more than 1 normal character: " + *wi);
  80             return;
  81         }
  82         case 3: {// 近接隣接演算種別エラー
  83             escapetag(*wi);
  84             errorsend("Adjacent kind error. Kind must be W or L: " + *wi);
  85             return;
  86         }
  87         case 4: {// 近接隣接演算距離エラー
  88             escapetag(*wi);
  89             char num[10];
  90             sprintf(num, "%d", MAXDIST);
  91             std::string msg(num);
  92             msg = "Adjacent operand &gt; MAXDIST " + msg + ": " + *wi;
  93             errorsend(msg);
  94             return;
  95         }
  96         case 5: {// 近接隣接演算フォーマットエラー
  97             escapetag(*wi);
  98             errorsend("Adjacent format error: " + *wi);
  99             return;
 100         }
 101         default:// 0 かその他正常
 102             break;
 103         }
 104     }
 105 
 106     // 入力があっても適切なクエリがひとつもなかった場合
 107     if (qrv.empty()) {
 108         errorsend("No valid expressions.");
 109         return;
 110     }
 111 
 112     // ラベルの出力
 113     wmesg->setTextFormat(XHTMLText);
 114     wmesg->setText(L"<div class=\"blk\"></div><br />Выражения: ");
 115 
 116     // ユーザ入力内容の表示
 117     // 変換済ユーザ入力
 118     WString wdata(udata, UTF8);
 119     wdata += opts;
 120     pmesg->setTextFormat(PlainText);
 121     pmesg->setStyleClass("exp");
 122     pmesg->setText(wdata);
 123 
 124     // char_string 用アロケータ(Shared Memory Resources)
 125     void_allocator valloc(segment3.get_segment_manager());
 126     // メッセージワーク
 127     std::string sm("");
 128     // 出力テーブル行初期化
 129     int row = 0;
 130     // KWIC タブを activate
 131     tabs->setCurrentIndex(tabs->indexOf(kwic));
 132     // テーブルのクリア(前回出力を消す)
 133     ctbl->clear();
 134 
 135     // ヘッダ1の出力 - 背景: 青; 文字: 灰
 136     // header 1: (0)No.<r> : (1){null}<l> : (2)Context<l> : (3)Position<c>
 137     WTableCell* cell00 = ctbl->elementAt(row, 0);
 138     cell00->addWidget(new Wt::WText(L"No.", XHTMLText));
 139     cell00->setStyleClass("seqh");
 140     WTableCell* cell01 = ctbl->elementAt(row, 1);
 141     cell01->addWidget(new Wt::WText(L"&nbsp;", XHTMLText));
 142     cell01->setStyleClass("preh");
 143     WTableCell* cell02 = ctbl->elementAt(row, 2);
 144     cell02->addWidget(new Wt::WText(L"Context", XHTMLText));
 145     cell02->setStyleClass("afth");
 146     WTableCell* cell03 = ctbl->elementAt(row, 3);
 147     cell03->addWidget(new Wt::WText(L"Position", XHTMLText));
 148     cell03->setStyleClass("posh");
 149     row++;
 150 
 151     // 単語式ごとに Word Tree を探索し,該当単語ノードを出力する
 152     int totalc = 0;           // トータル明細行
 153     for (std::vector<query>::iterator qit = qrv.begin();
 154             qit != qrv.end(); qit++) {
 155 
 156         // 式表示: タグセーフにして型変換し,式ヘッダ出力
 157         std::string ex(qit->qsrc);
 158         escapetag(ex);
 159         WString Exp(ex, UTF8);
 160         // header 2: (0-4){exp}<l> 背景: 青; 文字: 灰;
 161         WTableCell* cell10 = ctbl->elementAt(row, 0);
 162         cell10->addWidget(new Wt::WText(Exp, XHTMLText));
 163         cell10->setColumnSpan(4);
 164         cell10->setStyleClass("exd");
 165         row++;
 166 
 167         // 各種探索でヒットした単語情報の vector
 168         std::vector<wordinfo> twdvec;
 169         boost::u32regex rw;
 170 
 171         // 単語式の種別に応じて Tree を探索し,該当単語ノードを取得し,vector にセット
 172         if (qit->adjk) {
 173             // 近接隣接演算
 174             // Lemmatizing on なら Lemmatizer で入力を見出語変換する
 175             if (wbg1->checkedId() == 0) {
 176                 if (! qit->kind1)
 177                     lemmatize(qit->qexp1, lem);   // 検査ワード見出語変換
 178                 if (! qit->kind2)
 179                     lemmatize(qit->qexp2, lem);   // 対照ワード見出語変換
 180             }
 181             word_tree->find_adjacent_tree_set
 182             (qit->qexp1, qit->qexp2, qit->adjk, qit->adjd, twdvec, genrev);
 183         } else {
 184             if (qit->kind1) {
 185                 // 正規表現探索
 186                 try {
 187                     rw = boost::make_u32regex((qit->qexp1).c_str());
 188                     word_tree->find_regex_tree_set(rw, twdvec, genrev);
 189                 } catch (const std::exception& e) {
 190                     errorsend("Regular expression error: " + qit->qexp1);
 191                 }
 192             } else {
 193                 // 完全一致探索
 194                 // Lemmatizing on なら Lemmatizer で入力を見出語変換する
 195                 if (wbg1->checkedId() == 0)
 196                     lemmatize(qit->qexp1, lem);   // 見出語変換
 197                 word_tree->find_tree_set(qit->qexp1, twdvec, genrev);
 198             }
 199         }
 200 
 201         // コンコーダンス明細出力
 202         int seq = 1;              // 明細行カウンタ
 203         char_string keyc(valloc); // Shared Memory Map キー
 204 
 205         // 単語ノードごとのループ
 206         for (std::vector<wordinfo>::iterator ndit = twdvec.begin();
 207                 ndit != twdvec.end(); ndit++) {
 208 
 209             // MAXLINES 行を超えを検知したら,そこで終了
 210             if (row >= MAXLINES) {
 211                 ss << userip << " " << row << " rows proceeded.\n";
 212                 logging(ss.str().c_str(), INFO);
 213                 ssclear(ss);
 214                 goto END;
 215             }
 216 
 217             // 見出語,出現回数行を出力 - 背景 赤; 文字 薄紅
 218             WString Word(ndit->word.get(), UTF8);
 219             char wc[7];
 220             std::sprintf(wc, "%d", ndit->counter);
 221             WString Count(wc, UTF8);
 222             // header 3:(0-1)Выражение: {exp}<l>:(2){counter}<r>:(3){null}<l>
 223             WTableCell* cell20 = ctbl->elementAt(row, 0);
 224             cell20->addWidget(new Wt::WText(Word, XHTMLText));
 225             cell20->setStyleClass("lem");
 226             cell20->setColumnSpan(2);
 227             WTableCell* cell22 = ctbl->elementAt(row, 2);
 228             cell22->addWidget(new Wt::WText(Count, XHTMLText));
 229             cell22->setStyleClass("cnt");
 230             cell22->setColumnSpan(1);
 231             WTableCell* cell23 = ctbl->elementAt(row, 3);
 232             cell23->addWidget(new Wt::WText(L"&nbsp;", XHTMLText));
 233             cell23->setStyleClass("spc");
 234             row++;
 235 
 236             // Context ヒット明細行出力
 237             for (std::vector<offset_ptr<wpos> >::iterator wpi =
 238                         ndit->wposv.begin(); wpi != ndit->wposv.end(); wpi++) {
 239 
 240                 // 位置情報取得
 241                 int gen = (*wpi)->getgenre();   // ジャンル
 242                 int fno = (*wpi)->getfileno();  // 作品番号
 243                 int lno = (*wpi)->getlineno();  // 行番号
 244                 int lid = (*wpi)->getlineid();  // ID
 245                 int lps = (*wpi)->getlinepos(); // 行内出現アドレス
 246 
 247                 // 1.シーケンス番号編集
 248                 char wcp[22];
 249                 std::sprintf(wcp, "%d", seq++);
 250                 WString Seq(wcp, UTF8);
 251 
 252                 // 2.コンテクスト編集
 253                 // - "ジャンル:作品番号:行番号:ID" をキーに Corpus 本文を取得する
 254                 std::sprintf(wcp, "%02d:%04d:%06d:%06d",
 255                              gen, fno, lno, lid);
 256                 keyc = wcp;
 257                 Shmit mit = corpus_map->find(keyc);
 258                 // - カレント行を取得
 259                 std::string curln, preln, aftln;
 260                 if (mit != corpus_map->end())
 261                     curln = (mit->second).c_str();
 262                 else
 263                     std::cerr << "* corpus key: " << wcp << " not found.\n";
 264                 // - 前行を取得
 265                 if (mit != corpus_map->begin()) {
 266                     mit--;
 267                     // 同一作品なら前の行をセット
 268                     if (checkfno((mit->first).c_str(), fno))
 269                         preln = (mit->second).c_str();
 270                     else
 271                         preln = "";
 272                     mit++;
 273                 } else
 274                     std::cerr << "* preln is : " << wcp << " not found.\n";
 275                 // - 後行を取得
 276                 if (++mit != corpus_map->end())
 277                     // 同一作品ならあとの行をセット
 278                     if (checkfno((mit->first).c_str(), fno))
 279                         aftln = (mit->second).c_str();
 280                     else
 281                         aftln = "";
 282                 // - ヒット語/行の強調装飾
 283                 std::string out1, out2;
 284                 escapetag(curln);
 285                 escapetag(preln);
 286                 escapetag(aftln);
 287                 //emphword(curln, preln, aftln, out1, out2, lps);
 288                 emphword(curln, preln, aftln, out1, out2, lps, cprelen, caftlen); // debug
 289                 // - Context 前後行をセット
 290                 WString Pre(out1, UTF8);
 291                 WString Aft(out2, UTF8);
 292 
 293                 // 3.位置情報編集 (ジャンル:作品番号:行番号)
 294                 std::sprintf(wcp, "%02d:%04d:%06d", gen, fno, lno);
 295                 std::string posit(wcp);
 296                 // - "ジャンル:作品番号" をキーに TitleDB 情報を取得
 297                 std::string title;
 298                 std::sprintf(wcp, "%02d:%04d", gen, fno);
 299                 keyc = wcp; // char_string に変換
 300                 mit = tdb_map->find(keyc);
 301                 // - Title
 302                 if (mit != tdb_map->end()) {
 303                     title = (mit->second).c_str();
 304                     escapetag(title);
 305                 } else {
 306                     std::string s2 = keyc.c_str();
 307                     sm = "Key: " + s2 + " not found in tdb.";
 308                     title = "Unknown";
 309                     logging(sm.c_str(), WARN);
 310                 }
 311                 // - 位置情報/Title をリンク付きで出力
 312                 std::sprintf(wcp, "%04d.html#%06d", fno, lid);
 313                 std::string s3 = "<a href=\"" + URLbase + wcp
 314                                  + "\" target=\"_blank\" title=\""
 315                                  + title + "\">" + posit + "</a>";
 316                 WString Pos(s3, UTF8);
 317 
 318                 // 4.Context 明細行の出力 - 背景: 背景色; 文字: 文字色;
 319                 // contents:(0){seq}<r>:(1){pre}<l>:(2){aft}<l>:(3){pos}<c>
 320                 WTableCell* cell30 = ctbl->elementAt(row, 0);
 321                 cell30->addWidget(new Wt::WText(Seq, XHTMLText));
 322                 cell30->setStyleClass("seq");
 323                 WTableCell* cell31 = ctbl->elementAt(row, 1);
 324                 cell31->addWidget(new Wt::WText(Pre, XHTMLText));
 325                 cell31->setStyleClass("pre");
 326                 WTableCell* cell32 = ctbl->elementAt(row, 2);
 327                 cell32->addWidget(new Wt::WText(Aft, XHTMLText));
 328                 cell32->setStyleClass("aft");
 329                 WTableCell* cell33 = ctbl->elementAt(row, 3);
 330                 cell33->addWidget(new Wt::WText(Pos, XHTMLText));
 331                 cell33->setStyleClass("pos");
 332                 row++;
 333 
 334                 // 5.トータル明細出力カウンタのインクリメント
 335                 totalc++;
 336 
 337                 // 6.1000 行を超えるごとにロギング出力
 338                 if ((row > 1000) && ((row % 1000) == 0)) {
 339                     ss << userip << " " << row << " rows proceeded.\n";
 340                     logging(ss.str().c_str(), INFO);
 341                     ssclear(ss);
 342                 }
 343             }
 344         }
 345     }
 346 END:
 347     // 終了処理
 348     double elps = t.elapsed(); // 処理時間
 349     ss << userip << " elapse: " << elps << " sec; " << row << " rec;"
 350        << " genres: ";
 351     for (std::vector<int>::iterator gi = genrev.begin();
 352             gi != genrev.end(); gi++)
 353         ss << *gi << " ";
 354     ss << "\n";
 355     logging(ss.str().c_str(), INFO);
 356     ssclear(ss);
 357     // 終了メッセージ
 358     if (row >= MAXLINES) {
 359         // MAX 超過の場合: 警告
 360         ss << "KWIC proceeded over " << MAXLINES << " rows. Broken off."
 361            << "Reconsider your condition of Expression or Genres.\n";
 362         errorsend(ss.str());
 363         ssclear(ss);
 364     } else {
 365         // 正常終了の場合: 処理時間,出力 Context 数
 366         ss << "<div class=\"nrm\">Normally ended. Elapse time: " << elps
 367            << " sec; Output: " << totalc << " hit(s);</div>";
 368         WString emsg(ss.str());
 369         ssclear(ss);
 370         // 画面に終了メッセージをレイアウト
 371         cmesg->setTextFormat(XHTMLText);
 372         cmesg->setText(emsg);
 373     }
 374 }

/* [previous][next][first][last][top][bottom][index][help] */