The Battle for Wesnoth  1.19.0-dev
string_utils.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2005 - 2024
3  by Guillaume Melquiond <guillaume.melquiond@gmail.com>
4  Copyright (C) 2003 by David White <dave@whitevine.net>
5  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY.
13 
14  See the COPYING file for more details.
15 */
16 
17 #pragma once
18 
19 // Need this to get the default GETTEXT_DOMAIN for VGETTEXT/VNGETTEXT
20 #include "gettext.hpp"
21 
23 
24 #include <cstddef>
25 #include <ctime>
26 #include <string_view>
27 
28 class variable_set;
29 
30 namespace utils {
31 
32  namespace detail {
33  extern std::string(* evaluate_formula)(const std::string& formula);
34  }
35 
36 /**
37  * Determines if a string might contain variables to interpolate.
38  * This can allow one to skip future interpolations (plural -- if there is only
39  * one interpolation, the savings are not worth this check). In this spirit,
40  * precision is sacrificed in the name of efficiency; the check is quick and
41  * allows false positives, but there are no false negatives. (A false negative
42  * would lead to incorrect behavior, whereas a false positive leads to merely
43  * inefficient behavior.) In practice, false positives should be uncommon enough
44  * to not worry about.
45  */
46 inline bool might_contain_variables(const std::string &str)
47 { return str.find('$') != std::string::npos; }
48 
49 /**
50  * Function which will interpolate variables, starting with '$' in the string
51  * 'str' with the equivalent symbols in the given symbol table. If 'symbols'
52  * is nullptr, then game event variables will be used instead.
53  */
54 std::string interpolate_variables_into_string(const std::string &str, const std::map<std::string, t_string> * const symbols);
55 std::string interpolate_variables_into_string(const std::string &str, const std::map<std::string,std::string> * const symbols);
56 std::string interpolate_variables_into_string(const std::string &str, const variable_set& variables);
57 
58 /**
59  * Function that does the same as the above, for t_stringS.
60  * If a change was made, then the t_string's translation is done in this
61  * function, rather than at use. This limitation is due to the use of
62  * create-time interpolation, rather than use-time.
63  */
65 
66 /**
67  * Format a conjunctive list.
68  * @param empty The string to return for an empty list
69  * @param elems The list of entries in the list
70  * @return The elements of the list joined by "and".
71  */
72 std::string format_conjunct_list(const t_string& empty, const std::vector<t_string>& elems);
73 
74 /**
75  * Format a disjunctive list.
76  * @param empty The string to return for an empty list
77  * @param elems The list of entries in the list
78  * @return The elements of the list joined or "and".
79  */
80 std::string format_disjunct_list(const t_string& empty, const std::vector<t_string>& elems);
81 
82 /**
83  * Formats a timespan into human-readable text for player authentication functions.
84  *
85  * This is intentionally not a very thorough representation of time intervals.
86  * See <https://github.com/wesnoth/wesnoth/issues/6036> for more information.
87  *
88  * @param time The timespan in seconds.
89  * @param detailed Whether to display more specific values such as "3 months, 2 days,
90  * 30 minutes, and 1 second". If not specified or set to @a false, the
91  * return value will ONLY include most significant time unit (e.g. "3
92  * months").
93  * @return A human-readable timespan description.
94  *
95  * @note The implementation is not very precise because not all months in the Gregorian
96  * calendar have 30 days. Furthermore, it doesn't take into account leap years or
97  * leap seconds. If you need to account for those, you are better off importing
98  * a new library and providing it with more specific information about the start and
99  * end times of the interval; otherwise your next best option is to hire a fortune
100  * teller to manually service your requests every time instead of this function.
101  */
102 std::string format_timespan(std::time_t time, bool detailed = false);
103 }
104 
105 /**
106  * Implementation functions for the VGETTEXT and VNGETTEXT macros.
107  *
108  * DO NOT USE DIRECTLY unless you really know what you're doing.
109  * See https://github.com/wesnoth/wesnoth/issues/2716 for more info.
110  */
111 
112 std::string vgettext_impl(const char* domain, const char* msgid, const utils::string_map& symbols);
113 
114 std::string vngettext_impl(const char* domain,
115  const char* singular,
116  const char* plural,
117  int count,
118  const utils::string_map& symbols);
119 
120 /**
121  * Handy wrappers around interpolate_variables_into_string and gettext.
122  *
123  * These should cover most usecases. If you're not sure whether you want
124  * these macros or their implementation functions, use these. The only time
125  * you should need to use the implementation functions directly is to pass a
126  * different textdomain than the current value of GETTEXT_DOMAIN.
127  */
128 
129 #define VGETTEXT(msgid, ...) \
130  vgettext_impl(GETTEXT_DOMAIN, msgid, __VA_ARGS__)
131 
132 #define VNGETTEXT(msgid, msgid_plural, count, ...) \
133  vngettext_impl(GETTEXT_DOMAIN, msgid, msgid_plural, count, __VA_ARGS__)
134 
135 /**
136  * @brief Calculate the approximate edit distance of two strings.
137  *
138  * @param str_1 First string to compare.
139  * @param str_2 Second string to compare.
140  *
141  * @returns A score indicating how different the two strings are--the lower the score, the more similar the strings are.
142  *
143  * @note To avoid dynamic allocation, this function limits the number of characters that participate in the comparison.
144  */
145 [[nodiscard]] std::size_t edit_distance_approx(std::string_view str_1, std::string_view str_2) noexcept;
std::string vngettext_impl(const char *domain, const char *singular, const char *plural, int count, const utils::string_map &symbols)
std::string vgettext_impl(const char *domain, const char *msgid, const utils::string_map &symbols)
Implementation functions for the VGETTEXT and VNGETTEXT macros.
std::size_t edit_distance_approx(std::string_view str_1, std::string_view str_2) noexcept
Calculate the approximate edit distance of two strings.
std::string(* evaluate_formula)(const std::string &formula)
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
Function which will interpolate variables, starting with '$' in the string 'str' with the equivalent ...
std::string format_timespan(std::time_t time, bool detailed)
Formats a timespan into human-readable text for player authentication functions.
t_string interpolate_variables_into_tstring(const t_string &tstr, const variable_set &variables)
Function that does the same as the above, for t_stringS.
std::string format_disjunct_list(const t_string &empty, const std::vector< t_string > &elems)
Format a disjunctive list.
bool might_contain_variables(const std::string &str)
Determines if a string might contain variables to interpolate.
std::string format_conjunct_list(const t_string &empty, const std::vector< t_string > &elems)
Format a conjunctive list.
std::map< std::string, t_string > string_map