// Copyright 2010-2011, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Date comment style are following.
// - If the input number converts strictly 2 character with padding, comment
// format is like "HH" or "MM".
// e.g.) "YYYY/MM/DD HH:MM" -> "2011/01/30 03:20"
// - If the input number converts string without padding, comment format is
// like "H" or "M"
// e.g.) "Y/M/D H:M" -> "645/2/3 9:2"
#include "rewriter/date_rewriter.h"
#include <stdio.h>
#include <time.h>
#include <algorithm>
#include <string>
#include <vector>
#include "base/util.h"
#include "converter/segments.h"
#include "session/commands.pb.h"
#include "session/config_handler.h"
#include "session/config.pb.h"
namespace mozc {
// const char kDatePrefix[] = "\xE2\x86\x92"; // "→" (ATOK style)
const char *kDatePrefix = NULL;
namespace {
struct DateData {
const char *key;
const char *value;
const char *description;
int diff; // diff from the current time in day or month or year
};
const struct DateData kDateData[] = {
{
// きょう will show today's date
"\xE3\x81\x8D\xE3\x82\x87\xE3\x81\x86",
"\xE4\xBB\x8A\xE6\x97\xA5",
"\xE4\xBB\x8A\xE6\x97\xA5\xE3\x81\xAE\xE6\x97\xA5\xE4\xBB\x98",
0
},
{
// あした will show tomorrow's date
"\xE3\x81\x82\xE3\x81\x97\xE3\x81\x9F",
"\xE6\x98\x8E\xE6\x97\xA5",
"\xE6\x98\x8E\xE6\x97\xA5\xE3\x81\xAE\xE6\x97\xA5\xE4\xBB\x98",
1
},
{
// あす will show tomorrow's date
"\xE3\x81\x82\xE3\x81\x99",
"\xE6\x98\x8E\xE6\x97\xA5",
"\xE6\x98\x8E\xE6\x97\xA5\xE3\x81\xAE\xE6\x97\xA5\xE4\xBB\x98",
1
},
{
// さくじつ will show yesterday's date
"\xE3\x81\x95\xE3\x81\x8F\xE3\x81\x98\xE3\x81\xA4",
"\xE6\x98\xA8\xE6\x97\xA5",
"\xE6\x98\xA8\xE6\x97\xA5\xE3\x81\xAE\xE6\x97\xA5\xE4\xBB\x98",
-1
},
{
// きのう will show yesterday's date
"\xE3\x81\x8D\xE3\x81\xAE\xE3\x81\x86",
"\xE6\x98\xA8\xE6\x97\xA5",
"\xE6\x98\xA8\xE6\x97\xA5\xE3\x81\xAE\xE6\x97\xA5\xE4\xBB\x98",
-1
},
{
// おととい will show the date of 2 days ago
"\xE3\x81\x8A\xE3\x81\xA8\xE3\x81\xA8\xE3\x81\x84",
"\xE4\xB8\x80\xE6\x98\xA8\xE6\x97\xA5",
"2\xE6\x97\xA5\xE5\x89\x8D\xE3\x81\xAE\xE6\x97\xA5\xE4\xBB\x98",
-2
},
{
// おとつい will show the date of 2 days ago
"\xE3\x81\x8A\xE3\x81\xA8\xE3\x81\xA4\xE3\x81\x84",
"\xE4\xB8\x80\xE6\x98\xA8\xE6\x97\xA5",
"2\xE6\x97\xA5\xE5\x89\x8D\xE3\x81\xAE\xE6\x97\xA5\xE4\xBB\x98",
-2
},
{
// いっさくじつ will show the date of 2 days ago
"\xE3\x81\x84\xE3\x81\xA3\xE3\x81\x95\xE3\x81\x8F\xE3\x81\x98\xE3\x81\xA4",
"\xE4\xB8\x80\xE6\x98\xA8\xE6\x97\xA5",
"2\xE6\x97\xA5\xE5\x89\x8D\xE3\x81\xAE\xE6\x97\xA5\xE4\xBB\x98",
-2
},
{
// さきおととい will show the date of 3 days ago
"\xe3\x81\x95\xe3\x81\x8d\xe3\x81\x8a\xe3\x81\xa8"
"\xe3\x81\xa8\xe3\x81\x84",
"\xe4\xb8\x80\xe6\x98\xa8\xe6\x98\xa8\xe6\x97\xa5",
"3\xE6\x97\xA5\xE5\x89\x8D\xE3\x81\xAE\xE6\x97\xA5\xE4\xBB\x98",
-3
},
{
// あさって will show the date of 2 days from now
"\xE3\x81\x82\xE3\x81\x95\xE3\x81\xA3\xE3\x81\xA6",
"\xE6\x98\x8E\xE5\xBE\x8C\xE6\x97\xA5",
"\xE6\x98\x8E\xE5\xBE\x8C\xE6\x97\xA5\xE3\x81\xAE\xE6\x97\xA5\xE4\xBB\x98",
2,
},
{
// みょうごにち will show the date of 2 days from now
"\xE3\x81\xBF\xE3\x82\x87\xE3\x81\x86"
"\xE3\x81\x94\xE3\x81\xAB\xE3\x81\xA1",
"\xE6\x98\x8E\xE5\xBE\x8C\xE6\x97\xA5",
"\xE6\x98\x8E\xE5\xBE\x8C\xE6\x97\xA5\xE3\x81\xAE\xE6\x97\xA5\xE4\xBB\x98",
2
},
{
// しあさって will show the date of 3 days from now
"\xE3\x81\x97\xE3\x81\x82\xE3\x81\x95"
"\xE3\x81\xA3\xE3\x81\xA6",
"\xE6\x98\x8E\xE6\x98\x8E\xE5\xBE\x8C\xE6\x97\xA5",
"\xE6\x98\x8E\xE6\x98\x8E\xE5\xBE\x8C\xE6\x97\xA5\xE3\x81\xAE"
"\xE6\x97\xA5\xE4\xBB\x98",
3
}
};
const struct DateData kWeekDayData[] = {
{
// "にちようび"
"\xe3\x81\xab\xe3\x81\xa1\xe3\x82\x88\xe3\x81\x86\xe3\x81\xb3",
"\xe6\x97\xa5\xe6\x9b\x9c\xe6\x97\xa5",
"\xe6\xac\xa1\xe3\x81\xae\xe6\x97\xa5\xe6\x9b\x9c\xe6\x97\xa5",
0
},
{
// "げつようび"
"\xe3\x81\x92\xe3\x81\xa4\xe3\x82\x88\xe3\x81\x86\xe3\x81\xb3",
"\xe6\x9c\x88\xe6\x9b\x9c\xe6\x97\xa5",
"\xe6\xac\xa1\xe3\x81\xae\xe6\x9c\x88\xe6\x9b\x9c\xe6\x97\xa5",
1
},
{
// "かようび"
"\xe3\x81\x8b\xe3\x82\x88\xe3\x81\x86\xe3\x81\xb3",
"\xe7\x81\xab\xe6\x9b\x9c\xe6\x97\xa5",
"\xe6\xac\xa1\xe3\x81\xae\xe7\x81\xab\xe6\x9b\x9c\xe6\x97\xa5",
2
},
{
// "すいようび"
"\xe3\x81\x99\xe3\x81\x84\xe3\x82\x88\xe3\x81\x86\xe3\x81\xb3",
"\xe6\xb0\xb4\xe6\x9b\x9c\xe6\x97\xa5",
"\xe6\xac\xa1\xe3\x81\xae\xe6\xb0\xb4\xe6\x9b\x9c\xe6\x97\xa5",
3
},
{
// "もくようび"
"\xe3\x82\x82\xe3\x81\x8f\xe3\x82\x88\xe3\x81\x86\xe3\x81\xb3",
"\xe6\x9c\xa8\xe6\x9b\x9c\xe6\x97\xa5",
"\xe6\xac\xa1\xe3\x81\xae\xe6\x9c\xa8\xe6\x9b\x9c\xe6\x97\xa5",
4
},
{
// "きんようび"
"\xe3\x81\x8d\xe3\x82\x93\xe3\x82\x88\xe3\x81\x86\xe3\x81\xb3",
"\xe9\x87\x91\xe6\x9b\x9c\xe6\x97\xa5",
"\xe6\xac\xa1\xe3\x81\xae\xe9\x87\x91\xe6\x9b\x9c\xe6\x97\xa5",
5
},
{
// "どようび"
"\xe3\x81\xa9\xe3\x82\x88\xe3\x81\x86\xe3\x81\xb3",
"\xe5\x9c\x9f\xe6\x9b\x9c\xe6\x97\xa5",
"\xe6\xac\xa1\xe3\x81\xae\xe5\x9c\x9f\xe6\x9b\x9c\xe6\x97\xa5",
6
},
{
// "にちよう"
"\xE3\x81\xAB\xE3\x81\xA1\xE3\x82\x88\xE3\x81\x86",
"\xE6\x97\xA5\xE6\x9B\x9C",
"\xE6\xAC\xA1\xE3\x81\xAE\xE6\x97\xA5\xE6\x9B\x9C\xE6\x97\xA5",
0
},
{
// "げつよう"
"\xE3\x81\x92\xE3\x81\xA4\xE3\x82\x88\xE3\x81\x86",
"\xE6\x9C\x88\xE6\x9B\x9C",
"\xE6\xAC\xA1\xE3\x81\xAE\xE6\x9C\x88\xE6\x9B\x9C\xE6\x97\xA5",
1
},
{
// "かよう"
"\xE3\x81\x8B\xE3\x82\x88\xE3\x81\x86",
"\xE7\x81\xAB\xE6\x9B\x9C",
"\xE6\xAC\xA1\xE3\x81\xAE\xE7\x81\xAB\xE6\x9B\x9C\xE6\x97\xA5",
2
},
{
// "すいよう"
"\xE3\x81\x99\xE3\x81\x84\xE3\x82\x88\xE3\x81\x86",
"\xE6\xB0\xB4\xE6\x9B\x9C",
"\xE6\xAC\xA1\xE3\x81\xAE\xE6\xB0\xB4\xE6\x9B\x9C\xE6\x97\xA5",
3
},
{
// "もくよう"
"\xE3\x82\x82\xE3\x81\x8F\xE3\x82\x88\xE3\x81\x86",
"\xE6\x9C\xA8\xE6\x9B\x9C",
"\xE6\xAC\xA1\xE3\x81\xAE\xE6\x9C\xA8\xE6\x9B\x9C\xE6\x97\xA5",
4
},
{
// "きんよう"
"\xE3\x81\x8D\xE3\x82\x93\xE3\x82\x88\xE3\x81\x86",
"\xE9\x87\x91\xE6\x9B\x9C",
"\xE6\xAC\xA1\xE3\x81\xAE\xE9\x87\x91\xE6\x9B\x9C\xE6\x97\xA5",
5
},
{
// "どよう"
"\xE3\x81\xA9\xE3\x82\x88\xE3\x81\x86",
"\xE5\x9C\x9F\xE6\x9B\x9C",
"\xE6\xAC\xA1\xE3\x81\xAE\xE5\x9C\x9F\xE6\x9B\x9C\xE6\x97\xA5",
6
}
};
const struct DateData kYearData[] = {
{
// "ことし"
"\xE3\x81\x93\xE3\x81\xA8\xE3\x81\x97",
"\xE4\xBB\x8A\xE5\xB9\xB4",
"\xE4\xBB\x8A\xE5\xB9\xB4",
0
},
{
// "らいねん"
"\xE3\x82\x89\xE3\x81\x84\xE3\x81\xAD\xE3\x82\x93",
"\xE6\x9D\xA5\xE5\xB9\xB4",
"\xE6\x9D\xA5\xE5\xB9\xB4",
1
},
{
// "さくねん"
"\xE3\x81\x95\xE3\x81\x8F\xE3\x81\xAD\xE3\x82\x93",
"\xE6\x98\xA8\xE5\xB9\xB4",
"\xE6\x98\xA8\xE5\xB9\xB4",
-1
},
{
// "きょねん"
"\xE3\x81\x8D\xE3\x82\x87\xE3\x81\xAD\xE3\x82\x93",
"\xE5\x8E\xBB\xE5\xB9\xB4",
"\xE5\x8E\xBB\xE5\xB9\xB4",
-1
},
{
// "おととし"
"\xE3\x81\x8A\xE3\x81\xA8\xE3\x81\xA8\xE3\x81\x97",
"\xE4\xB8\x80\xE6\x98\xA8\xE5\xB9\xB4",
"\xE4\xB8\x80\xE6\x98\xA8\xE5\xB9\xB4",
-2
},
{
// "さらいねん"
"\xE3\x81\x95\xE3\x82\x89\xE3\x81\x84\xE3\x81\xAD\xE3\x82\x93",
"\xE5\x86\x8D\xE6\x9D\xA5\xE5\xB9\xB4",
"\xE5\x86\x8D\xE6\x9D\xA5\xE5\xB9\xB4",
2
}
};
const struct DateData kMonthData[] = {
{
// "こんげつ"
"\xE3\x81\x93\xE3\x82\x93\xE3\x81\x92\xE3\x81\xA4",
"\xE4\xBB\x8A\xE6\x9C\x88",
"\xE4\xBB\x8A\xE6\x9C\x88",
0
},
{
// "らいげつ"
"\xE3\x82\x89\xE3\x81\x84\xE3\x81\x92\xE3\x81\xA4",
"\xE6\x9D\xA5\xE6\x9C\x88",
"\xE6\x9D\xA5\xE6\x9C\x88",
1
},
{
// "せんげつ"
"\xE3\x81\x9B\xE3\x82\x93\xE3\x81\x92\xE3\x81\xA4",
"\xE5\x85\x88\xE6\x9C\x88",
"\xE5\x85\x88\xE6\x9C\x88",
-1
},
{
// "せんせんげつ"
"\xE3\x81\x9B\xE3\x82\x93\xE3\x81\x9B\xE3\x82\x93\xE3\x81\x92\xE3\x81\xA4",
"\xE5\x85\x88\xE3\x80\x85\xE6\x9C\x88",
"\xE5\x85\x88\xE3\x80\x85\xE6\x9C\x88",
-2
},
{
// "さらいげつ"
"\xE3\x81\x95\xE3\x82\x89\xE3\x81\x84\xE3\x81\x92\xE3\x81\xA4",
"\xE5\x86\x8D\xE6\x9D\xA5\xE6\x9C\x88",
"\xE5\x86\x8D\xE6\x9D\xA5\xE6\x9C\x88",
2
}
};
const struct DateData kCurrentTimeData[] = {
{
// "いま"
"\xE3\x81\x84\xE3\x81\xBE",
"\xE4\xBB\x8A",
"\xE7\x8F\xBE\xE5\x9C\xA8\xE3\x81\xAE\xE6\x99\x82\xE5\x88\xBB",
0
},
{
// "じこく"
"\xE3\x81\x98\xE3\x81\x93\xE3\x81\x8F",
"\xE6\x99\x82\xE5\x88\xBB",
"\xE7\x8F\xBE\xE5\x9C\xA8\xE3\x81\xAE\xE6\x99\x82\xE5\x88\xBB",
0
}
};
const struct DateData kDateAndCurrentTimeData[] = {
{
// "にちじ"
"\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\x98",
"\xE6\x97\xA5\xE6\x99\x82",
"\xE7\x8F\xBE\xE5\x9C\xA8\xE3\x81\xAE\xE6\x97\xA5\xE6\x99\x82",
0
},
};
struct YearData {
int ad; // AD year
const char *era; // Japanese year a.k.a, GENGO
};
const YearData kEraData[] = {
{ 645, "\xE5\xA4\xA7\xE5\x8C\x96" }, // "大化"
{ 650, "\xE7\x99\xBD\xE9\x9B\x89" }, // "白雉"
{ 686, "\xE6\x9C\xB1\xE9\xB3\xA5" }, // "朱鳥"
{ 701, "\xE5\xA4\xA7\xE5\xAE\x9D" }, // "大宝"
{ 704, "\xE6\x85\xB6\xE9\x9B\xB2" }, // "慶雲"
{ 708, "\xE5\x92\x8C\xE9\x8A\x85" }, // "和銅"
{ 715, "\xE9\x9C\x8A\xE4\xBA\x80" }, // "霊亀
{ 717, "\xE9\xA4\x8A\xE8\x80\x81" }, // "養老
{ 724, "\xE7\xA5\x9E\xE4\xBA\x80" }, // "神亀
{ 729, "\xE5\xA4\xA9\xE5\xB9\xB3" }, // "天平
// "天平感宝"
{ 749, "\xE5\xA4\xA9\xE5\xB9\xB3\xE6\x84\x9F\xE5\xAE\x9D" },
// "天平勝宝"
{ 749, "\xE5\xA4\xA9\xE5\xB9\xB3\xE5\x8B\x9D\xE5\xAE\x9D" },
// "天平宝字"
{ 757, "\xE5\xA4\xA9\xE5\xB9\xB3\xE5\xAE\x9D\xE5\xAD\x97" },
// "天平神護"
{ 765, "\xE5\xA4\xA9\xE5\xB9\xB3\xE7\xA5\x9E\xE8\xAD\xB7" },
// "神護景雲"
{ 767, "\xE7\xA5\x9E\xE8\xAD\xB7\xE6\x99\xAF\xE9\x9B\xB2" },
{ 770, "\xE5\xAE\x9D\xE4\xBA\x80" }, // "宝亀"
{ 781, "\xE5\xA4\xA9\xE5\xBF\x9C" }, // "天応"
{ 782, "\xE5\xBB\xB6\xE6\x9A\xA6" }, // "延暦"
{ 806, "\xE5\xA4\xA7\xE5\x90\x8C" }, // "大同"
{ 810, "\xE5\xBC\x98\xE4\xBB\x81" }, // "弘仁"
{ 824, "\xE5\xA4\xA9\xE9\x95\xB7" }, // "天長"
{ 834, "\xE6\x89\xBF\xE5\x92\x8C" }, // "承和"
{ 848, "\xE5\x98\x89\xE7\xA5\xA5" }, // "嘉祥"
{ 851, "\xE4\xBB\x81\xE5\xAF\xBF" }, // "仁寿"
{ 854, "\xE6\x96\x89\xE8\xA1\xA1" }, // "斉衡"
{ 857, "\xE5\xA4\xA9\xE5\xAE\x89" }, // "天安"
{ 859, "\xE8\xB2\x9E\xE8\xA6\xB3" }, // "貞観"
{ 877, "\xE5\x85\x83\xE6\x85\xB6" }, // "元慶"
{ 885, "\xE4\xBB\x81\xE5\x92\x8C" }, // "仁和"
{ 889, "\xE5\xAF\x9B\xE5\xB9\xB3" }, // "寛平"
{ 898, "\xE6\x98\x8C\xE6\xB3\xB0" }, // "昌泰"
{ 901, "\xE5\xBB\xB6\xE5\x96\x9C" }, // "延喜"
{ 923, "\xE5\xBB\xB6\xE9\x95\xB7" }, // "延長"
{ 931, "\xE6\x89\xBF\xE5\xB9\xB3" }, // "承平"
{ 938, "\xE5\xA4\xA9\xE6\x85\xB6" }, // "天慶"
{ 947, "\xE5\xA4\xA9\xE6\x9A\xA6" }, // "天暦"
{ 957, "\xE5\xA4\xA9\xE5\xBE\xB3" }, // "天徳"
{ 961, "\xE5\xBF\x9C\xE5\x92\x8C" }, // "応和"
{ 964, "\xE5\xBA\xB7\xE4\xBF\x9D" }, // "康保"
{ 968, "\xE5\xAE\x89\xE5\x92\x8C" }, // "安和"
{ 970, "\xE5\xA4\xA9\xE7\xA6\x84" }, // "天禄"
{ 973, "\xE5\xA4\xA9\xE5\xBB\xB6" }, // "天延"
{ 976, "\xE8\xB2\x9E\xE5\x85\x83" }, // "貞元"
{ 978, "\xE5\xA4\xA9\xE5\x85\x83" }, // "天元"
{ 983, "\xE6\xB0\xB8\xE8\xA6\xB3" }, // "永観"
{ 985, "\xE5\xAF\x9B\xE5\x92\x8C" }, // "寛和"
{ 987, "\xE6\xB0\xB8\xE5\xBB\xB6" }, // "永延"
{ 989, "\xE6\xB0\xB8\xE7\xA5\x9A" }, // "永祚"
{ 990, "\xE6\xAD\xA3\xE6\x9A\xA6" }, // "正暦"
{ 995, "\xE9\x95\xB7\xE5\xBE\xB3" }, // "長徳"
{ 999, "\xE9\x95\xB7\xE4\xBF\x9D" }, // "長保"
{ 1004, "\xE5\xAF\x9B\xE5\xBC\x98" }, // "寛弘"
{ 1012, "\xE9\x95\xB7\xE5\x92\x8C" }, // "長和"
{ 1017, "\xE5\xAF\x9B\xE4\xBB\x81" }, // "寛仁"
{ 1021, "\xE6\xB2\xBB\xE5\xAE\x89" }, // "治安"
{ 1024, "\xE4\xB8\x87\xE5\xAF\xBF" }, // "万寿"
{ 1028, "\xE9\x95\xB7\xE5\x85\x83" }, // "長元"
{ 1037, "\xE9\x95\xB7\xE6\x9A\xA6" }, // "長暦"
{ 1040, "\xE9\x95\xB7\xE4\xB9\x85" }, // "長久"
{ 1044, "\xE5\xAF\x9B\xE5\xBE\xB3" }, // "寛徳"
{ 1046, "\xE6\xB0\xB8\xE6\x89\xBF" }, // "永承"
{ 1053, "\xE5\xA4\xA9\xE5\x96\x9C" }, // "天喜"
{ 1058, "\xE5\xBA\xB7\xE5\xB9\xB3" }, // "康平"
{ 1065, "\xE6\xB2\xBB\xE6\x9A\xA6" }, // "治暦"
{ 1069, "\xE5\xBB\xB6\xE4\xB9\x85" }, // "延久"
{ 1074, "\xE6\x89\xBF\xE4\xBF\x9D" }, // "承保"
{ 1077, "\xE6\x89\xBF\xE6\x9A\xA6" }, // "承暦"
{ 1081, "\xE6\xB0\xB8\xE4\xBF\x9D" }, // "永保"
{ 1084, "\xE5\xBF\x9C\xE5\xBE\xB3" }, // "応徳"
{ 1087, "\xE5\xAF\x9B\xE6\xB2\xBB" }, // "寛治"
{ 1094, "\xE5\x98\x89\xE4\xBF\x9D" }, // "嘉保"
{ 1096, "\xE6\xB0\xB8\xE9\x95\xB7" }, // "永長"
{ 1097, "\xE6\x89\xBF\xE5\xBE\xB3" }, // "承徳"
{ 1099, "\xE5\xBA\xB7\xE5\x92\x8C" }, // "康和"
{ 1104, "\xE9\x95\xB7\xE6\xB2\xBB" }, // "長治"
{ 1106, "\xE5\x98\x89\xE6\x89\xBF" }, // "嘉承"
{ 1108, "\xE5\xA4\xA9\xE4\xBB\x81" }, // "天仁"
{ 1110, "\xE5\xA4\xA9\xE6\xB0\xB8" }, // "天永"
{ 1113, "\xE6\xB0\xB8\xE4\xB9\x85" }, // "永久"
{ 1118, "\xE5\x85\x83\xE6\xB0\xB8" }, // "元永"
{ 1120, "\xE4\xBF\x9D\xE5\xAE\x89" }, // "保安"
{ 1124, "\xE5\xA4\xA9\xE6\xB2\xBB" }, // "天治"
{ 1126, "\xE5\xA4\xA7\xE6\xB2\xBB" }, // "大治"
{ 1131, "\xE5\xA4\xA9\xE6\x89\xBF" }, // "天承"
{ 1132, "\xE9\x95\xB7\xE6\x89\xBF" }, // "長承"
{ 1135, "\xE4\xBF\x9D\xE5\xBB\xB6" }, // "保延"
{ 1141, "\xE6\xB0\xB8\xE6\xB2\xBB" }, // "永治"
{ 1142, "\xE5\xBA\xB7\xE6\xB2\xBB" }, // "康治"
{ 1144, "\xE5\xA4\xA9\xE9\xA4\x8A" }, // "天養"
{ 1145, "\xE4\xB9\x85\xE5\xAE\x89" }, // "久安"
{ 1151, "\xE4\xBB\x81\xE5\xB9\xB3" }, // "仁平"
{ 1154, "\xE4\xB9\x85\xE5\xAF\xBF" }, // "久寿"
{ 1156, "\xE4\xBF\x9D\xE5\x85\x83" }, // "保元"
{ 1159, "\xE5\xB9\xB3\xE6\xB2\xBB" }, // "平治"
{ 1160, "\xE6\xB0\xB8\xE6\x9A\xA6" }, // "永暦"
{ 1161, "\xE5\xBF\x9C\xE4\xBF\x9D" }, // "応保"
{ 1163, "\xE9\x95\xB7\xE5\xAF\x9B" }, // "長寛"
{ 1165, "\xE6\xB0\xB8\xE4\xB8\x87" }, // "永万"
{ 1166, "\xE4\xBB\x81\xE5\xAE\x89" }, // "仁安"
{ 1169, "\xE5\x98\x89\xE5\xBF\x9C" }, // "嘉応"
{ 1171, "\xE6\x89\xBF\xE5\xAE\x89" }, // "承安"
{ 1175, "\xE5\xAE\x89\xE5\x85\x83" }, // "安元"
{ 1177, "\xE6\xB2\xBB\xE6\x89\xBF" }, // "治承"
{ 1181, "\xE9\xA4\x8A\xE5\x92\x8C" }, // "養和"
{ 1182, "\xE5\xAF\xBF\xE6\xB0\xB8" }, // "寿永"
{ 1184, "\xE5\x85\x83\xE6\x9A\xA6" }, // "元暦"
{ 1185, "\xE6\x96\x87\xE6\xB2\xBB" }, // "文治"
{ 1190, "\xE5\xBB\xBA\xE4\xB9\x85" }, // "建久"
{ 1199, "\xE6\xAD\xA3\xE6\xB2\xBB" }, // "正治"
{ 1201, "\xE5\xBB\xBA\xE4\xBB\x81" }, // "建仁"
{ 1204, "\xE5\x85\x83\xE4\xB9\x85" }, // "元久"
{ 1206, "\xE5\xBB\xBA\xE6\xB0\xB8" }, // "建永"
{ 1207, "\xE6\x89\xBF\xE5\x85\x83" }, // "承元"
{ 1211, "\xE5\xBB\xBA\xE6\x9A\xA6" }, // "建暦"
{ 1213, "\xE5\xBB\xBA\xE4\xBF\x9D" }, // "建保"
{ 1219, "\xE6\x89\xBF\xE4\xB9\x85" }, // "承久"
{ 1222, "\xE8\xB2\x9E\xE5\xBF\x9C" }, // "貞応"
{ 1224, "\xE5\x85\x83\xE4\xBB\x81" }, // "元仁"
{ 1225, "\xE5\x98\x89\xE7\xA6\x84" }, // "嘉禄"
{ 1227, "\xE5\xAE\x89\xE8\xB2\x9E" }, // "安貞"
{ 1229, "\xE5\xAF\x9B\xE5\x96\x9C" }, // "寛喜"
{ 1232, "\xE8\xB2\x9E\xE6\xB0\xB8" }, // "貞永"
{ 1233, "\xE5\xA4\xA9\xE7\xA6\x8F" }, // "天福"
{ 1234, "\xE6\x96\x87\xE6\x9A\xA6" }, // "文暦"
{ 1235, "\xE5\x98\x89\xE7\xA6\x8E" }, // "嘉禎"
{ 1238, "\xE6\x9A\xA6\xE4\xBB\x81" }, // "暦仁"
{ 1239, "\xE5\xBB\xB6\xE5\xBF\x9C" }, // "延応"
{ 1240, "\xE4\xBB\x81\xE6\xB2\xBB" }, // "仁治"
{ 1243, "\xE5\xAF\x9B\xE5\x85\x83" }, // "寛元"
{ 1247, "\xE5\xAE\x9D\xE6\xB2\xBB" }, // "宝治"
{ 1249, "\xE5\xBB\xBA\xE9\x95\xB7" }, // "建長"
{ 1256, "\xE5\xBA\xB7\xE5\x85\x83" }, // "康元"
{ 1257, "\xE6\xAD\xA3\xE5\x98\x89" }, // "正嘉"
{ 1259, "\xE6\xAD\xA3\xE5\x85\x83" }, // "正元"
{ 1260, "\xE6\x96\x87\xE5\xBF\x9C" }, // "文応"
{ 1261, "\xE5\xBC\x98\xE9\x95\xB7" }, // "弘長"
{ 1264, "\xE6\x96\x87\xE6\xB0\xB8" }, // "文永"
{ 1275, "\xE5\xBB\xBA\xE6\xB2\xBB" }, // "建治"
{ 1278, "\xE5\xBC\x98\xE5\xAE\x89" }, // "弘安"
{ 1288, "\xE6\xAD\xA3\xE5\xBF\x9C" }, // "正応"
{ 1293, "\xE6\xB0\xB8\xE4\xBB\x81" }, // "永仁"
{ 1299, "\xE6\xAD\xA3\xE5\xAE\x89" }, // "正安"
{ 1302, "\xE4\xB9\xBE\xE5\x85\x83" }, // "乾元"
{ 1303, "\xE5\x98\x89\xE5\x85\x83" }, // "嘉元"
{ 1306, "\xE5\xBE\xB3\xE6\xB2\xBB" }, // "徳治"
{ 1308, "\xE5\xBB\xB6\xE6\x85\xB6" }, // "延慶"
{ 1311, "\xE5\xBF\x9C\xE9\x95\xB7" }, // "応長"
{ 1312, "\xE6\xAD\xA3\xE5\x92\x8C" }, // "正和"
{ 1317, "\xE6\x96\x87\xE4\xBF\x9D" }, // "文保"
{ 1319, "\xE5\x85\x83\xE5\xBF\x9C" }, // "元応"
{ 1321, "\xE5\x85\x83\xE4\xBA\xA8" }, // "元亨"
{ 1324, "\xE6\xAD\xA3\xE4\xB8\xAD" }, // "正中"
{ 1326, "\xE5\x98\x89\xE6\x9A\xA6" }, // "嘉暦"
// "元徳" is used for both south and north courts.
{ 1329, "\xE5\x85\x83\xE5\xBE\xB3" }, // "元徳"
{ 1331, "\xE5\x85\x83\xE5\xBC\x98" }, // "元弘"
{ 1334, "\xE5\xBB\xBA\xE6\xAD\xA6" }, // "建武"
{ 1336, "\xE5\xBB\xB6\xE5\x85\x83" }, // "延元"
{ 1340, "\xE8\x88\x88\xE5\x9B\xBD" }, // "興国"
{ 1346, "\xE6\xAD\xA3\xE5\xB9\xB3" }, // "正平"
{ 1370, "\xE5\xBB\xBA\xE5\xBE\xB3" }, // "建徳"
{ 1372, "\xE6\x96\x87\xE4\xB8\xAD" }, // "文中"
{ 1375, "\xE5\xA4\xA9\xE6\x8E\x88" }, // "天授"
{ 1381, "\xE5\xBC\x98\xE5\x92\x8C" }, // "弘和"
{ 1384, "\xE5\x85\x83\xE4\xB8\xAD" }, // "元中"
{ 1390, "\xE6\x98\x8E\xE5\xBE\xB3" }, // "明徳"
{ 1394, "\xE5\xBF\x9C\xE6\xB0\xB8" }, // "応永"
{ 1428, "\xE6\xAD\xA3\xE9\x95\xB7" }, // "正長"
{ 1429, "\xE6\xB0\xB8\xE4\xBA\xAB" }, // "永享"
{ 1441, "\xE5\x98\x89\xE5\x90\x89" }, // "嘉吉"
{ 1444, "\xE6\x96\x87\xE5\xAE\x89" }, // "文安"
{ 1449, "\xE5\xAE\x9D\xE5\xBE\xB3" }, // "宝徳"
{ 1452, "\xE4\xBA\xAB\xE5\xBE\xB3" }, // "享徳"
{ 1455, "\xE5\xBA\xB7\xE6\xAD\xA3" }, // "康正"
{ 1457, "\xE9\x95\xB7\xE7\xA6\x84" }, // "長禄"
{ 1460, "\xE5\xAF\x9B\xE6\xAD\xA3" }, // "寛正"
{ 1466, "\xE6\x96\x87\xE6\xAD\xA3" }, // "文正"
{ 1467, "\xE5\xBF\x9C\xE4\xBB\x81" }, // "応仁"
{ 1469, "\xE6\x96\x87\xE6\x98\x8E" }, // "文明"
{ 1487, "\xE9\x95\xB7\xE4\xBA\xAB" }, // "長享"
{ 1489, "\xE5\xBB\xB6\xE5\xBE\xB3" }, // "延徳"
{ 1492, "\xE6\x98\x8E\xE5\xBF\x9C" }, // "明応"
{ 1501, "\xE6\x96\x87\xE4\xBA\x80" }, // "文亀"
{ 1504, "\xE6\xB0\xB8\xE6\xAD\xA3" }, // "永正"
{ 1521, "\xE5\xA4\xA7\xE6\xB0\xB8" }, // "大永"
{ 1528, "\xE4\xBA\xAB\xE7\xA6\x84" }, // "享禄"
{ 1532, "\xE5\xA4\xA9\xE6\x96\x87" }, // "天文"
{ 1555, "\xE5\xBC\x98\xE6\xB2\xBB" }, // "弘治"
{ 1558, "\xE6\xB0\xB8\xE7\xA6\x84" }, // "永禄"
{ 1570, "\xE5\x85\x83\xE4\xBA\x80" }, // "元亀"
{ 1573, "\xE5\xA4\xA9\xE6\xAD\xA3" }, // "天正"
{ 1592, "\xE6\x96\x87\xE7\xA6\x84" }, // "文禄"
{ 1596, "\xE6\x85\xB6\xE9\x95\xB7" }, // "慶長"
{ 1615, "\xE5\x85\x83\xE5\x92\x8C" }, // "元和"
{ 1624, "\xE5\xAF\x9B\xE6\xB0\xB8" }, // "寛永"
{ 1644, "\xE6\xAD\xA3\xE4\xBF\x9D" }, // "正保"
{ 1648, "\xE6\x85\xB6\xE5\xAE\x89" }, // "慶安"
{ 1652, "\xE6\x89\xBF\xE5\xBF\x9C" }, // "承応"
{ 1655, "\xE6\x98\x8E\xE6\x9A\xA6" }, // "明暦"
{ 1658, "\xE4\xB8\x87\xE6\xB2\xBB" }, // "万治"
{ 1661, "\xE5\xAF\x9B\xE6\x96\x87" }, // "寛文"
{ 1673, "\xE5\xBB\xB6\xE5\xAE\x9D" }, // "延宝"
{ 1681, "\xE5\xA4\xA9\xE5\x92\x8C" }, // "天和"
{ 1684, "\xE8\xB2\x9E\xE4\xBA\xAB" }, // "貞享"
{ 1688, "\xE5\x85\x83\xE7\xA6\x84" }, // "元禄"
{ 1704, "\xE5\xAE\x9D\xE6\xB0\xB8" }, // "宝永"
{ 1711, "\xE6\xAD\xA3\xE5\xBE\xB3" }, // "正徳"
{ 1716, "\xE4\xBA\xAB\xE4\xBF\x9D" }, // "享保"
{ 1736, "\xE5\x85\x83\xE6\x96\x87" }, // "元文"
{ 1741, "\xE5\xAF\x9B\xE4\xBF\x9D" }, // "寛保"
{ 1744, "\xE5\xBB\xB6\xE4\xBA\xAB" }, // "延享"
{ 1748, "\xE5\xAF\x9B\xE5\xBB\xB6" }, // "寛延"
{ 1751, "\xE5\xAE\x9D\xE6\x9A\xA6" }, // "宝暦"
{ 1764, "\xE6\x98\x8E\xE5\x92\x8C" }, // "明和"
{ 1772, "\xE5\xAE\x89\xE6\xB0\xB8" }, // "安永"
{ 1781, "\xE5\xA4\xA9\xE6\x98\x8E" }, // "天明"
{ 1789, "\xE5\xAF\x9B\xE6\x94\xBF" }, // "寛政"
{ 1801, "\xE4\xBA\xAB\xE5\x92\x8C" }, // "享和"
{ 1804, "\xE6\x96\x87\xE5\x8C\x96" }, // "文化"
{ 1818, "\xE6\x96\x87\xE6\x94\xBF" }, // "文政"
{ 1830, "\xE5\xA4\xA9\xE4\xBF\x9D" }, // "天保"
{ 1844, "\xE5\xBC\x98\xE5\x8C\x96" }, // "弘化"
{ 1848, "\xE5\x98\x89\xE6\xB0\xB8" }, // "嘉永"
{ 1854, "\xE5\xAE\x89\xE6\x94\xBF" }, // "安政"
{ 1860, "\xE4\xB8\x87\xE5\xBB\xB6" }, // "万延"
{ 1861, "\xE6\x96\x87\xE4\xB9\x85" }, // "文久"
{ 1864, "\xE5\x85\x83\xE6\xB2\xBB" }, // "元治"
{ 1865, "\xE6\x85\xB6\xE5\xBF\x9C" }, // "慶応"
{ 1868, "\xE6\x98\x8E\xE6\xB2\xBB" }, // "明治"
{ 1912, "\xE5\xA4\xA7\xE6\xAD\xA3" }, // "大正"
{ 1926, "\xE6\x98\xAD\xE5\x92\x8C" }, // "昭和"
{ 1989, "\xE5\xB9\xB3\xE6\x88\x90" }, // "平成"
};
const YearData kNorthEraData[] = {
// "元徳" is used for both south and north courts.
{ 1329, "\xE5\x85\x83\xE5\xBE\xB3" }, // "元徳"
{ 1332, "\xE6\xAD\xA3\xE6\x85\xB6" }, // "正慶"
{ 1334, "\xE5\xBB\xBA\xE6\xAD\xA6" }, // "建武"
{ 1338, "\xE6\x9A\xA6\xE5\xBF\x9C" }, // "暦応"
{ 1342, "\xE5\xBA\xB7\xE6\xB0\xB8" }, // "康永"
{ 1345, "\xE8\xB2\x9E\xE5\x92\x8C" }, // "貞和"
{ 1350, "\xE8\xA6\xB3\xE5\xBF\x9C" }, // "観応"
{ 1352, "\xE6\x96\x87\xE5\x92\x8C" }, // "文和"
{ 1356, "\xE5\xBB\xB6\xE6\x96\x87" }, // "延文"
{ 1361, "\xE5\xBA\xB7\xE5\xAE\x89" }, // "康安"
{ 1362, "\xE8\xB2\x9E\xE6\xB2\xBB" }, // "貞治"
{ 1368, "\xE5\xBF\x9C\xE5\xAE\x89" }, // "応安"
{ 1375, "\xE6\xB0\xB8\xE5\x92\x8C" }, // "永和"
{ 1379, "\xE5\xBA\xB7\xE6\x9A\xA6" }, // "康暦"
{ 1381, "\xE6\xB0\xB8\xE5\xBE\xB3" }, // "永徳"
{ 1384, "\xE8\x87\xB3\xE5\xBE\xB3" }, // "至徳"
{ 1387, "\xE5\x98\x89\xE6\x85\xB6" }, // "嘉慶"
{ 1389, "\xE5\xBA\xB7\xE5\xBF\x9C" }, // "康応"
{ 1390, "\xE6\x98\x8E\xE5\xBE\xB3" }, // "明徳"
};
const char *kWeekDayString[] = {
"\xE6\x97\xA5", // "日"
"\xE6\x9C\x88", // "月"
"\xE7\x81\xAB", // "火"
"\xE6\xB0\xB4", // "水"
"\xE6\x9C\xA8", // "木"
"\xE9\x87\x91", // "金"
"\xE5\x9C\x9F", // "土"
};
// Converts a prefix and year number to Japanese Kanji Representation
// arguments :
// - input "prefix" : a japanese style year counter prefix.
// - input "year" : represent integer must be smaller than 100.
// - output "result" : will be stored candidate strings
// If the input year is invalid ( accept only [ 1 - 99 ] ) , this function
// returns false and clear output vector.
bool ExpandYear(const string &prefix, int year, vector<string> *result) {
DCHECK(result);
if (year <= 0 || year >= 100) {
result->clear();
return false;
}
if (year == 1) {
// "元年"
result->push_back(prefix + "\xE5\x85\x83");
return true;
}
result->push_back(prefix + Util::SimpleItoa(year));
string arabic = Util::SimpleItoa(year);
vector<Util::NumberString> output;
Util::ArabicToKanji(arabic, &output);
for (int i = 0; i < output.size(); i++) {
if (output[i].style == Util::NumberString::NUMBER_KANJI) {
result->push_back(prefix + output[i].value);
}
}
return true;
}
void Insert(Segment *segment,
const Segment::Candidate &base_candidate,
int position,
const string &value,
const char *description,
const char *prefix) {
Segment::Candidate *c = segment->insert_candidate(position);
DCHECK(c);
c->Init();
c->lid = base_candidate.lid;
c->rid = base_candidate.rid;
c->cost = base_candidate.cost;
c->value = value;
c->key = base_candidate.key;
c->content_key = base_candidate.content_key;
c->attributes |= Segment::Candidate::NO_LEARNING;
c->attributes |= Segment::Candidate::NO_VARIANTS_EXPANSION;
if (description != NULL) {
c->description = description;
}
if (prefix != NULL) {
c->prefix = prefix;
}
}
enum {
REWRITE_YEAR,
REWRITE_DATE,
REWRITE_MONTH,
REWRITE_CURRENT_TIME,
REWRITE_DATE_AND_CURRENT_TIME
};
bool ADtoERAforCourt(const YearData *data, int size,
int year, vector<string> *results) {
for (int i = size - 1; i >= 0; --i) {
if (i == size - 1 && year > data[i].ad) {
ExpandYear(data[i].era, year - data[i].ad + 1, results);
return true;
} else if (i > 0 && data[i-1].ad < year && year <= data[i].ad) {
// have two representations:
// 1989 -> "昭和64" and "平成元"
if (year == data[i].ad) {
ExpandYear(data[i].era, 1, results);
}
ExpandYear(data[i-1].era, year - data[i-1].ad + 1, results);
return true;
} else if (i == 0 && data[i].ad <= year) {
if (year == data[i].ad) {
ExpandYear(data[i].era, 1, results);
} else {
ExpandYear(data[i-1].era, year - data[i-1].ad + 1, results);
}
return true;
}
}
return false;
}
// Checkes given date is valid or not.
// Over 24 hour expression is allowed in this function.
// Acceptable hour is between 0 and 29.
bool IsValidTime(uint32 hour, uint32 minute) {
if (hour >= 30 || minute >= 60) {
return false;
} else {
return true;
}
}
// Returns February last day.
// This function deals with leap year with Gregorian calendar.
uint32 GetFebruaryLastDay(uint32 year) {
uint32 february_end = (year % 4 == 0) ? 29 : 28;
if (year % 100 == 0 && year % 400 != 0) {
february_end = 28;
}
return february_end;
}
// Checkes given date is valid or not.
bool IsValidDate(uint32 year, uint32 month, uint32 day) {
if (day < 1) {
return false;
}
if (year == 0 || year > 2100) {
return false;
}
switch (month) {
case 2: {
if (day > GetFebruaryLastDay(year)) {
return false;
} else {
return true;
}
}
case 4: case 6: case 9: case 11: {
if (day > 30) {
return false;
} else {
return true;
}
}
case 1: case 3: case 5: case 7: case 8: case 10: case 12: {
if (day > 31) {
return false;
} else {
return true;
}
}
default: {
return false;
}
}
}
// Checks given date is valid or not in this year
bool IsValidDateInThisYear(uint32 month, uint32 day) {
struct tm t_st;
if (!Util::GetTmWithOffsetSecond(&t_st, 0)) {
LOG(ERROR) << "GetTmWithOffsetSecond() failed";
return false;
}
return IsValidDate(t_st.tm_year + 1900, month, day);
}
} // namespace
// convert AD to Japanese ERA.
// The results will have multiple variants.
bool DateRewriter::ADtoERA(int year, vector<string> *results) const {
if (year < 645 || year > 2050) { // TODO(taku) is it enough?
return false;
}
// The order is south to north.
vector<string> eras;
bool r = false;
r = ADtoERAforCourt(kEraData, arraysize(kEraData), year, &eras);
if (year > 1331 && year < 1393) {
r |= ADtoERAforCourt(kNorthEraData, arraysize(kNorthEraData),
year, &eras);
}
// 1334 requires dedupe
for (int i = 0; i < eras.size(); ++i) {
bool found = false;
for (int j = 0; j < i; ++j) {
if (eras[j] == eras[i]) {
found = true;
}
}
if (!found) {
results->push_back(eras[i]);
}
}
return r;
}
bool DateRewriter::ConvertTime(uint32 hour, uint32 min,
vector<string> *results) const {
DCHECK(results);
if (!IsValidTime(hour, min)) {
return false;
}
results->push_back(Util::StringPrintf("%d:%2.2d", hour, min));
// "H時MM分"
results->push_back(Util::StringPrintf("%d\xE6\x99\x82%2.2d\xE5\x88\x86",
hour, min));
if (min == 30) {
// "H時半"
results->push_back(Util::StringPrintf("%d\xE6\x99\x82\xE5\x8D\x8A", hour));
}
if ((hour % 24) * 60 + min < 720) { // 0:00 -- 11:59
// "午前H時MM分"
results->push_back(Util::StringPrintf(
"\xE5\x8D\x88\xE5\x89\x8D%d\xE6\x99\x82%d\xE5\x88\x86",
hour % 24, min));
if (min == 30) {
// "午前H時半"
results->push_back(Util::StringPrintf(
"\xE5\x8D\x88\xE5\x89\x8D%d\xE6\x99\x82\xE5\x8D\x8A",
hour % 24));
}
} else {
// "午後H時MM分"
results->push_back(Util::StringPrintf(
"\xE5\x8D\x88\xE5\xBE\x8C%d\xE6\x99\x82%d\xE5\x88\x86",
(hour - 12) % 24, min));
if (min == 30) {
// "午後H時半"
results->push_back(Util::StringPrintf(
"\xE5\x8D\x88\xE5\xBE\x8C%d\xE6\x99\x82\xE5\x8D\x8A",
(hour - 12) % 24));
}
}
return true;
}
bool DateRewriter::ConvertDateWithYear(uint32 year, uint32 month, uint32 day,
vector<string> *results) const {
DCHECK(results);
if (!IsValidDate(year, month, day)) {
return false;
}
// "Y/MM/DD"
results->push_back(Util::StringPrintf("%d/%2.2d/%2.2d", year, month, day));
// "Y-MM-DD"
results->push_back(Util::StringPrintf("%d-%2.2d-%2.2d", year, month, day));
// "Y年M月D日"
results->push_back(Util::StringPrintf(
"%d\xE5\xB9\xB4%d\xE6\x9C\x88%d\xE6\x97\xA5",
year, month, day));
return true;
}
bool DateRewriter::ConvertDateWithoutYear(uint32 month, uint32 day,
vector<string> *results) const {
DCHECK(results);
if (!IsValidDateInThisYear(month, day)) {
return false;
}
// "MM/DD"
results->push_back(Util::StringPrintf("%2.2d/%2.2d", month, day));
// "M月D日"
results->push_back(Util::StringPrintf("%d\xE6\x9C\x88%d\xE6\x97\xA5",
month, day));
return true;
}
bool DateRewriter::RewriteTime(Segment *segment,
const char *key,
const char *value,
const char *description,
int type, int diff) const {
if (segment->key() != key) { // only exact match
return false;
}
const size_t kMinSize = 10;
const size_t size = min(kMinSize, segment->candidates_size());
for (size_t cand_idx = 0; cand_idx < size; ++cand_idx) {
const Segment::Candidate &cand = segment->candidate(cand_idx);
if (cand.value != value) {
continue;
}
// Date candidates are too many, therefore highest candidate show at most
// 3rd.
// TODO(nona): learn date candidate even if the date is chaned.
const size_t kMinimumDateCandidateIdx = 3;
const size_t insert_idx = (size < kMinimumDateCandidateIdx) ?
size : max(cand_idx + 1, kMinimumDateCandidateIdx);
struct tm t_st;
string tmp;
vector<string> era;
if (type == REWRITE_DATE) {
if (!Util::GetTmWithOffsetSecond(&t_st, diff * 86400)) {
LOG(ERROR) << "GetTmWithOffsetSecond() failed";
return false;
}
vector<string> results;
ConvertDateWithYear(t_st.tm_year + 1900, t_st.tm_mon + 1, t_st.tm_mday,
&results);
if (ADtoERA(t_st.tm_year + 1900, &era) && !era.empty()) {
// "平成Y年M月D日"
results.push_back(Util::StringPrintf(
"%s\xE5\xB9\xB4%d\xE6\x9C\x88%d\xE6\x97\xA5",
era[0].c_str(), t_st.tm_mon + 1, t_st.tm_mday));
}
// "WDAY曜日"
results.push_back(Util::StringPrintf("%s\xE6\x9B\x9C\xE6\x97\xA5",
kWeekDayString[t_st.tm_wday]));
for (vector<string>::reverse_iterator rit = results.rbegin();
rit != results.rend(); ++rit) {
Insert(segment, cand, insert_idx , *rit, description, kDatePrefix);
}
return true;
} else if (type == REWRITE_MONTH) {
if (!Util::GetCurrentTm(&t_st)) {
LOG(ERROR) << "GetCurrentTm failed";
return false;
}
const int month = (t_st.tm_mon + diff + 12) % 12 + 1;
// "月"
tmp = Util::StringPrintf("%d\xE6\x9C\x88", month);
Insert(segment, cand, insert_idx, tmp, description, kDatePrefix);
tmp = Util::StringPrintf("%d", month);
Insert(segment, cand, insert_idx, tmp, description, kDatePrefix);
return true;
} else if (type == REWRITE_YEAR) {
if (!Util::GetCurrentTm(&t_st)) {
LOG(ERROR) << "GetCurrentTm failed";
return false;
}
const int year = (t_st.tm_year + diff + 1900);
if (ADtoERA(year, &era) && !era.empty()) {
// "年"
tmp = Util::StringPrintf("%s\xE5\xB9\xB4", era[0].c_str());
Insert(segment, cand, insert_idx, tmp, description, kDatePrefix);
}
// "年"
tmp = Util::StringPrintf("%d\xE5\xB9\xB4", year);
Insert(segment, cand, insert_idx, tmp, description, kDatePrefix);
tmp = Util::StringPrintf("%d", year);
Insert(segment, cand, insert_idx, tmp, description, kDatePrefix);
return true;
} else if (type == REWRITE_CURRENT_TIME) {
if (!Util::GetCurrentTm(&t_st)) {
LOG(ERROR) << "GetCurrentTm failed";
return false;
}
vector<string> times;
ConvertTime(t_st.tm_hour, t_st.tm_min, ×);
for (vector<string>::reverse_iterator rit = times.rbegin();
rit != times.rend(); ++rit) {
Insert(segment, cand, insert_idx, *rit, description, kDatePrefix);
}
return true;
} else if (type == REWRITE_DATE_AND_CURRENT_TIME) {
if (!Util::GetCurrentTm(&t_st)) {
LOG(ERROR) << "GetCurrentTm failed";
return false;
}
// Y/MM/DD H:MM
tmp = Util::StringPrintf("%d/%2.2d/%2.2d %2d:%2.2d",
t_st.tm_year + 1900,
t_st.tm_mon + 1,
t_st.tm_mday,
t_st.tm_hour,
t_st.tm_min);
Insert(segment, cand, insert_idx, tmp, description, kDatePrefix);
}
return true;
}
return false;
}
bool DateRewriter::RewriteDate(Segment *segment) const {
for (size_t i = 0; i < arraysize(kDateData); ++i) {
if (RewriteTime(segment,
kDateData[i].key, kDateData[i].value,
kDateData[i].description,
REWRITE_DATE,
kDateData[i].diff)) {
VLOG(1) << "RewriteDate: "
<< kDateData[i].key << " " << kDateData[i].value;
return true;
}
}
return false;
}
bool DateRewriter::RewriteMonth(Segment *segment) const {
for (size_t i = 0; i < arraysize(kMonthData); ++i) {
if (RewriteTime(segment,
kMonthData[i].key, kMonthData[i].value,
kMonthData[i].description,
REWRITE_MONTH,
kMonthData[i].diff)) {
VLOG(1) << "RewriteMonth: "
<< kMonthData[i].key << " " << kMonthData[i].value;
return true;
}
}
return false;
}
bool DateRewriter::RewriteYear(Segment *segment) const {
for (size_t i = 0; i < arraysize(kYearData); ++i) {
if (RewriteTime(segment,
kYearData[i].key, kYearData[i].value,
kYearData[i].description,
REWRITE_YEAR,
kYearData[i].diff)) {
VLOG(1) << "RewriteYear: "
<< kYearData[i].key << " " << kYearData[i].value;
return true;
}
}
return false;
}
bool DateRewriter::RewriteWeekday(Segment *segment) const {
struct tm t_st;
if (!Util::GetCurrentTm(&t_st)) {
LOG(ERROR) << "GetCurrentTm failed";
return false;
}
for (size_t i = 0; i < arraysize(kWeekDayData); ++i) {
const int weekday = kWeekDayData[i].diff % 7;
const int additional_dates = (weekday + 7 - t_st.tm_wday) % 7;
if (RewriteTime(segment,
kWeekDayData[i].key, kWeekDayData[i].value,
kWeekDayData[i].description,
REWRITE_DATE,
additional_dates)) {
VLOG(1) << "RewriteWeekday: "
<< kWeekDayData[i].key << " " << kWeekDayData[i].value;
return true;
}
}
return false;
}
bool DateRewriter::RewriteCurrentTime(Segment *segment) const {
for (size_t i = 0; i < arraysize(kCurrentTimeData); ++i) {
if (RewriteTime(segment,
kCurrentTimeData[i].key, kCurrentTimeData[i].value,
kCurrentTimeData[i].description,
REWRITE_CURRENT_TIME,
0)) {
VLOG(1) << "RewriteCurrentTime: "
<< kCurrentTimeData[i].key << " "
<< kCurrentTimeData[i].value;
return true;
}
}
return false;
}
bool DateRewriter::RewriteDateAndCurrentTime(Segment *segment) const {
for (size_t i = 0; i < arraysize(kDateAndCurrentTimeData); ++i) {
if (RewriteTime(segment,
kDateAndCurrentTimeData[i].key,
kDateAndCurrentTimeData[i].value,
kDateAndCurrentTimeData[i].description,
REWRITE_DATE_AND_CURRENT_TIME,
0)) {
VLOG(1) << "RewriteDateAndCurrentTime: "
<< kDateAndCurrentTimeData[i].key << " "
<< kDateAndCurrentTimeData[i].value;
return true;
}
}
return false;
}
bool DateRewriter::RewriteEra(Segment *current_segment,
const Segment &next_segment) const {
if (current_segment->candidates_size() <= 0 ||
next_segment.candidates_size() <= 0) {
LOG(ERROR) << "Candidate size is 0";
return false;
}
const string ¤t_key = current_segment->key();
const string &next_value = next_segment.candidate(0).value;
// "年"
if (next_value != "\xE5\xB9\xB4") {
return false;
}
if (Util::GetScriptType(current_key) != Util::NUMBER) {
return false;
}
const size_t len = Util::CharsLen(current_key);
if (len < 3 || len > 4) {
LOG(WARNING) << "Too long year";
return false;
}
string year_str;
Util::FullWidthAsciiToHalfWidthAscii(current_key,
&year_str);
const uint32 year = atoi32(year_str.c_str());
vector<string> results;
if (!ADtoERA(year, &results)) {
return false;
}
const int kInsertPosition = 2;
const int position
= min(kInsertPosition,
static_cast<int>(current_segment->candidates_size()));
// "和暦"
const char kDescription[] = "\xE5\x92\x8C\xE6\x9A\xA6";
for (int i = static_cast<int>(results.size()) - 1; i >= 0; --i) {
Insert(current_segment,
current_segment->candidate(0),
position,
results[i],
kDescription, NULL);
current_segment->mutable_candidate(position)->attributes
&= ~Segment::Candidate::NO_VARIANTS_EXPANSION;
}
return true;
}
bool DateRewriter::RewriteFourDigits(Segment *segment) const {
const string ¤t_value = segment->key();
if (Util::GetScriptType(current_value) != Util::NUMBER) {
return false;
}
const size_t len = Util::CharsLen(current_value);
if (len != 4) {
return false;
}
string number_str;
Util::FullWidthAsciiToHalfWidthAscii(current_value,
&number_str);
const uint32 number = atoi32(number_str.c_str());
const uint32 upper_number = number / 100;
const uint32 lower_number = number % 100;
const Segment::Candidate &cand = segment->candidate(0);
bool is_modified = false;
vector<string> result;
is_modified |= ConvertDateWithoutYear(upper_number, lower_number, &result);
for (size_t i = 0; i < result.size(); ++i) {
// Always insert after last candidate.
const int position = static_cast<int>(segment->candidates_size());
// "日付"
Insert(segment, cand, position, result[i], "\xE6\x97\xA5\xE4\xBB\x98",
kDatePrefix);
}
result.clear();
is_modified |= ConvertTime(upper_number, lower_number, &result);
for (size_t i = 0; i < result.size(); ++i) {
// Always insert after last candidate.
const int position = static_cast<int>(segment->candidates_size());
// "時刻"
Insert(segment, cand, position, result[i], "\xE6\x99\x82\xE5\x88\xBB",
kDatePrefix);
}
return is_modified;
}
DateRewriter::DateRewriter() {}
DateRewriter::~DateRewriter() {}
int DateRewriter::capability() const {
return RewriterInterface::CONVERSION;
}
bool DateRewriter::Rewrite(Segments *segments) const {
if (!GET_CONFIG(use_date_conversion)) {
VLOG(2) << "no use_date_conversion";
return false;
}
bool modified = false;
for (size_t i = segments->history_segments_size();
i < segments->segments_size(); ++i) {
Segment *seg = segments->mutable_segment(i);
if (seg == NULL) {
LOG(ERROR) << "Segment is NULL";
return false;
}
if (RewriteDate(seg) || RewriteWeekday(seg) ||
RewriteMonth(seg) || RewriteYear(seg) ||
RewriteCurrentTime(seg) ||
RewriteDateAndCurrentTime(seg)) {
modified = true;
} else if (i + 1 < segments->segments_size() &&
RewriteEra(seg, segments->segment(i + 1))) {
modified = true;
++i; // skip one more
}
modified |= RewriteFourDigits(seg);
}
return modified;
}
} // namespace mozc