public CardReplacer(Th10Converter parent, bool hideUntriedCards)
            {
                this.evaluator = new MatchEvaluator(match =>
                {
                    var number = int.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
                    var type   = match.Groups[2].Value.ToUpperInvariant();

                    if (CardTable.ContainsKey(number))
                    {
                        if (type == "N")
                        {
                            if (hideUntriedCards)
                            {
                                var cards = parent.allScoreData.ClearData[CharaWithTotal.Total].Cards;
                                SpellCard card;
                                if (!cards.TryGetValue(number, out card) || !card.HasTried())
                                {
                                    return("??????????");
                                }
                            }

                            return(CardTable[number].Name);
                        }
                        else
                        {
                            return(CardTable[number].Level.ToString());
                        }
                    }
                    else
                    {
                        return(match.ToString());
                    }
                });
            }
            public PracticeReplacer(Th10Converter parent)
            {
                this.evaluator = new MatchEvaluator(match =>
                {
                    var level = LevelParser.Parse(match.Groups[1].Value);
                    var chara = (CharaWithTotal)CharaParser.Parse(match.Groups[2].Value);
                    var stage = StageParser.Parse(match.Groups[3].Value);

                    if (level == Level.Extra)
                    {
                        return(match.ToString());
                    }
                    if (stage == Stage.Extra)
                    {
                        return(match.ToString());
                    }

                    if (parent.allScoreData.ClearData.ContainsKey(chara))
                    {
                        var key       = new LevelStagePair(level, stage);
                        var practices = parent.allScoreData.ClearData[chara].Practices;
                        return(practices.ContainsKey(key)
                            ? Utils.ToNumberString(practices[key].Score * 10) : "0");
                    }
                    else
                    {
                        return("0");
                    }
                });
            }
            public ScoreReplacer(Th10Converter parent)
            {
                this.evaluator = new MatchEvaluator(match =>
                {
                    var level = LevelParser.Parse(match.Groups[1].Value);
                    var chara = (CharaWithTotal)CharaParser.Parse(match.Groups[2].Value);
                    var rank  = Utils.ToZeroBased(
                        int.Parse(match.Groups[3].Value, CultureInfo.InvariantCulture));
                    var type = int.Parse(match.Groups[4].Value, CultureInfo.InvariantCulture);

                    var ranking = parent.allScoreData.ClearData[chara].Rankings[level][rank];
                    switch (type)
                    {
                    case 1:         // name
                        return(Encoding.Default.GetString(ranking.Name).Split('\0')[0]);

                    case 2:         // score
                        return(Utils.ToNumberString((ranking.Score * 10) + ranking.ContinueCount));

                    case 3:         // stage
                        if (ranking.DateTime > 0)
                        {
                            return((ranking.StageProgress == StageProgress.Extra)
                                    ? "Not Clear" : ranking.StageProgress.ToShortName());
                        }
                        else
                        {
                            return(StageProgress.None.ToShortName());
                        }

                    case 4:         // date & time
                        if (ranking.DateTime > 0)
                        {
                            return(new DateTime(1970, 1, 1).AddSeconds(ranking.DateTime).ToLocalTime()
                                   .ToString("yyyy/MM/dd HH:mm:ss", CultureInfo.CurrentCulture));
                        }
                        else
                        {
                            return("----/--/-- --:--:--");
                        }

                    case 5:         // slow
                        if (ranking.DateTime > 0)
                        {
                            return(Utils.Format("{0:F3}%", ranking.SlowRate));
                        }
                        else
                        {
                            return("-----%");
                        }

                    default:        // unreachable
                        return(match.ToString());
                    }
                });
            }
            public CollectRateReplacer(Th10Converter parent)
            {
                this.evaluator = new MatchEvaluator(match =>
                {
                    var level = LevelWithTotalParser.Parse(match.Groups[1].Value);
                    var chara = CharaWithTotalParser.Parse(match.Groups[2].Value);
                    var stage = StageWithTotalParser.Parse(match.Groups[3].Value);
                    var type  = int.Parse(match.Groups[4].Value, CultureInfo.InvariantCulture);

                    if (stage == StageWithTotal.Extra)
                    {
                        return(match.ToString());
                    }

                    Func <SpellCard, bool> findByStage;
                    if (stage == StageWithTotal.Total)
                    {
                        findByStage = (card => true);
                    }
                    else
                    {
                        findByStage = (card => CardTable[card.Id].Stage == (Stage)stage);
                    }

                    Func <SpellCard, bool> findByLevel = (card => true);
                    switch (level)
                    {
                    case LevelWithTotal.Total:
                        // Do nothing
                        break;

                    case LevelWithTotal.Extra:
                        findByStage = (card => CardTable[card.Id].Stage == Stage.Extra);
                        break;

                    default:
                        findByLevel = (card => card.Level == (Level)level);
                        break;
                    }

                    Func <SpellCard, bool> findByType;
                    if (type == 1)
                    {
                        findByType = (card => card.ClearCount > 0);
                    }
                    else
                    {
                        findByType = (card => card.TrialCount > 0);
                    }

                    return(parent.allScoreData.ClearData[chara].Cards.Values
                           .Count(Utils.MakeAndPredicate(findByLevel, findByStage, findByType))
                           .ToString(CultureInfo.CurrentCulture));
                });
            }
            public ClearReplacer(Th10Converter parent)
            {
                this.evaluator = new MatchEvaluator(match =>
                {
                    var level = LevelParser.Parse(match.Groups[1].Value);
                    var chara = (CharaWithTotal)CharaParser.Parse(match.Groups[2].Value);

                    var rankings = parent.allScoreData.ClearData[chara].Rankings[level]
                                   .Where(ranking => ranking.DateTime > 0);
                    var stageProgress = (rankings.Count() > 0)
                        ? rankings.Max(ranking => ranking.StageProgress) : StageProgress.None;

                    return((stageProgress == StageProgress.Extra)
                        ? "Not Clear" : stageProgress.ToShortName());
                });
            }
            public CharaExReplacer(Th10Converter parent)
            {
                this.evaluator = new MatchEvaluator(match =>
                {
                    var level = LevelWithTotalParser.Parse(match.Groups[1].Value);
                    var chara = CharaWithTotalParser.Parse(match.Groups[2].Value);
                    var type  = int.Parse(match.Groups[3].Value, CultureInfo.InvariantCulture);

                    Func <ClearData, long> getValueByType;
                    Func <long, string> toString;
                    if (type == 1)
                    {
                        getValueByType = (data => data.TotalPlayCount);
                        toString       = Utils.ToNumberString;
                    }
                    else if (type == 2)
                    {
                        getValueByType = (data => data.PlayTime);
                        toString       = (value => new Time(value).ToString());
                    }
                    else
                    {
                        if (level == LevelWithTotal.Total)
                        {
                            getValueByType = (data => data.ClearCounts.Values.Sum());
                        }
                        else
                        {
                            getValueByType = (data => data.ClearCounts[(Level)level]);
                        }
                        toString = Utils.ToNumberString;
                    }

                    Func <AllScoreData, long> getValueByChara;
                    if (chara == CharaWithTotal.Total)
                    {
                        getValueByChara = (allData => allData.ClearData.Values
                                           .Where(data => data.Chara != chara).Sum(getValueByType));
                    }
                    else
                    {
                        getValueByChara = (allData => getValueByType(allData.ClearData[chara]));
                    }

                    return(toString(getValueByChara(parent.allScoreData)));
                });
            }
            public CareerReplacer(Th10Converter parent)
            {
                this.evaluator = new MatchEvaluator(match =>
                {
                    var number = int.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
                    var chara  = CharaWithTotalParser.Parse(match.Groups[2].Value);
                    var type   = int.Parse(match.Groups[3].Value, CultureInfo.InvariantCulture);

                    Func <SpellCard, int> getCount;
                    if (type == 1)
                    {
                        getCount = (card => card.ClearCount);
                    }
                    else
                    {
                        getCount = (card => card.TrialCount);
                    }

                    var cards = parent.allScoreData.ClearData[chara].Cards;
                    if (number == 0)
                    {
                        return(Utils.ToNumberString(cards.Values.Sum(getCount)));
                    }
                    else if (CardTable.ContainsKey(number))
                    {
                        SpellCard card;
                        if (cards.TryGetValue(number, out card))
                        {
                            return(Utils.ToNumberString(getCount(card)));
                        }
                        else
                        {
                            return("0");
                        }
                    }
                    else
                    {
                        return(match.ToString());
                    }
                });
            }