<commit_before>/*
 * Copyright (C) 2017 Tmplt <<EMAIL>>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <array>
#include <cctype>

#include <fuzzywuzzy.hpp>

#include "item.hpp"
#include "utils.hpp"
#include "common.hpp"
#include "algorithm.hpp"

static constexpr int fuzzy_min = 75;

namespace bookwyrm {

exacts_t::exacts_t(const std::unique_ptr<cliparser> &cli)
{
    /* Parse the year which may have a prefixed modifier. */
    std::tie(ymod, year) = [&cli]() -> std::pair<year_mod, int> {
        const auto year_str = cli->get("year");
        if (year_str.empty()) return {year_mod::equal, empty};

        const auto start = std::find_if(year_str.cbegin(), year_str.cend(), [](char c) {
            return std::isdigit(c);
        });

        try {
            /*
             * NOTE: this approach allows the year to be represented as a float
             * (which stoi truncates to an int) and allows appended not-digits.
             * Will this cause problems?
             */
            const auto year = std::stoi(string(start, year_str.cend()));

            if (start != year_str.cbegin()) {
                /* There is a modifier in front of the year */
                string mod_str(year_str.cbegin(), start);
                year_mod mod;

                if (mod_str == "=>")
                    mod = year_mod::eq_gt;
                else if (mod_str == "=<")
                    mod = year_mod::eq_lt;
                else if (mod_str == ">")
                    mod = year_mod::gt;
                else if (mod_str == "<")
                    mod = year_mod::lt;
                else
                    throw value_error("unrecognised year modifier '" + mod_str + '\'');

                return {mod, year};
            }

            return {year_mod::equal, year};
        } catch (const value_error &err) {
            throw err;
        } catch (const std::exception &err) {
            throw value_error("malformed year");
        }
    }();

    auto parse_number = [&cli](string &&opt) -> int {
        auto value_str = cli->get(opt);
        if (value_str.empty()) return empty;

        try {
            return std::stoi(value_str);
        } catch (std::exception &err) {
            throw value_error("malformed value '" + value_str + "' for argument --" + opt);
        }
    };

    edition = parse_number("edition");
    volume  = parse_number("volume");
    number  = parse_number("number");
    pages   = parse_number("pages");
}

nonexacts_t::nonexacts_t(const std::unique_ptr<cliparser> &cli)
{
    authors   = cli->get_many("author");
    title     = cli->get("title");
    serie     = cli->get("serie");
    publisher = cli->get("publisher");
    journal   = cli->get("journal");
}

exacts_t::exacts_t(const std::map<string, int> &dict)
{
    auto get_value = [&dict](string &&key) -> int {
        auto elem = dict.find(key);
        return elem == dict.end() ? empty : elem->second;
    };

    year    = get_value("year");
    edition = get_value("edition");
    volume  = get_value("volume");
    number  = get_value("number");
    pages   = get_value("pages");
}

nonexacts_t::nonexacts_t(const std::map<string, string> &dict, const vector<string> &authors)
{
    auto get_value = [&dict](string &&key) -> string {
        const auto elem = dict.find(key);
        return elem == dict.end() ? "" : elem->second;
    };

    title     = get_value("title");
    serie     = get_value("serie");
    publisher = get_value("publisher");<commit_msg>const consistency<commit_after>/*
 * Copyright (C) 2017 Tmplt <<EMAIL>>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <array>
#include <cctype>

#include <fuzzywuzzy.hpp>

#include "item.hpp"
#include "utils.hpp"
#include "common.hpp"
#include "algorithm.hpp"

static constexpr int fuzzy_min = 75;

namespace bookwyrm {

exacts_t::exacts_t(const std::unique_ptr<cliparser> &cli)
{
    /* Parse the year which may have a prefixed modifier. */
    std::tie(ymod, year) = [&cli]() -> std::pair<year_mod, int> {
        const auto year_str = cli->get("year");
        if (year_str.empty()) return {year_mod::equal, empty};

        const auto start = std::find_if(year_str.cbegin(), year_str.cend(), [](char c) {
            return std::isdigit(c);
        });

        try {
            /*
             * NOTE: this approach allows the year to be represented as a float
             * (which stoi truncates to an int) and allows appended not-digits.
             * Will this cause problems?
             */
            const auto year = std::stoi(string(start, year_str.cend()));

            if (start != year_str.cbegin()) {
                /* There is a modifier in front of the year */
                string mod_str(year_str.cbegin(), start);
                year_mod mod;

                if (mod_str == "=>")
                    mod = year_mod::eq_gt;
                else if (mod_str == "=<")
                    mod = year_mod::eq_lt;
                else if (mod_str == ">")
                    mod = year_mod::gt;
                else if (mod_str == "<")
                    mod = year_mod::lt;
                else
                    throw value_error("unrecognised year modifier '" + mod_str + '\'');

                return {mod, year};
            }

            return {year_mod::equal, year};
        } catch (const value_error &err) {
            throw err;
        } catch (const std::exception &err) {
            throw value_error("malformed year");
        }
    }();

    auto parse_number = [&cli](string &&opt) -> int {
        auto value_str = cli->get(opt);
        if (value_str.empty()) return empty;

        try {
            return std::stoi(value_str);
        } catch (std::exception &err) {
            throw value_error("malformed value '" + value_str + "' for argument --" + opt);
        }
    };

    edition = parse_number("edition");
    volume  = parse_number("volume");
    number  = parse_number("number");
    pages   = parse_number("pages");
}

nonexacts_t::nonexacts_t(const std::unique_ptr<cliparser> &cli)
{
    authors   = cli->get_many("author");
    title     = cli->get("title");
    serie     = cli->get("serie");
    publisher = cli->get("publisher");
    journal   = cli->get("journal");
}

exacts_t::exacts_t(const std::map<string, int> &dict)
{
    auto get_value = [&dict](string &&key) -> int {
        const auto elem = dict.find(key);
        return elem == dict.end() ? empty : elem->second;
    };

    year    = get_value("year");
    edition = get_value("edition");
    volume  = get_value("volume");
    number  = get_value("number");
    pages   = get_value("pages");
}

nonexacts_t::nonexacts_t(const std::map<string, string> &dict, const vector<string> &authors)
{
    auto get_value = [&dict](string &&key) -> string {
        const auto elem = dict.find(key);
        return elem == dict.end() ? "" : elem->second;
    };

    title     = get_value("title");
    serie     = get_value("serie");
    publisher = get_value("publisher");
{'fraction_non_alphanumeric': 0.13532555879494654, 'fraction_numerical': 0.0017006802721088435, 'mean_word_length': 2.2971565879054867, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6665309', 'n_tokens_mistral': 2517, 'n_tokens_neox': 2436, 'n_words': 707}