mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-29 20:23:55 +00:00
prototype separate function call for match and prefix matching
This commit is contained in:
parent
77b33a879d
commit
2f59ab8cfa
@ -13,15 +13,38 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
int prefixMatch(const std::string& s1, const std::string& s2)
|
||||||
|
{
|
||||||
|
if (s1.size() < s2.size())
|
||||||
|
{
|
||||||
|
if (s2.compare(0, s1.size(), s1.c_str()) == 0)
|
||||||
|
{
|
||||||
|
return s2.size()-s1.size();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return std::string::npos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (s1.compare(0, s2.size(), s2.c_str()) == 0)
|
||||||
|
{
|
||||||
|
return s1.size()-s2.size();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return std::string::npos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Levenshtein distance function code generated by chatgpt
|
// Levenshtein distance function code generated by chatgpt
|
||||||
int levenshteinDistance(const std::string &s1, const std::string &s2) {
|
int levenshteinDistance(const std::string &s1, const std::string &s2) {
|
||||||
size_t len1 = s1.size(), len2 = s2.size();
|
size_t len1 = s1.size(), len2 = s2.size();
|
||||||
std::vector<std::vector<int>> dp(len1 + 1, std::vector<int>(len2 + 1));
|
std::vector<std::vector<int>> dp(len1 + 1, std::vector<int>(len2 + 1));
|
||||||
|
|
||||||
for(size_t i = 0; i <= len1; ++i)
|
for(size_t ii = 0; ii <= len1; ++ii)
|
||||||
dp[i][0] = static_cast<int>(i);
|
dp[ii][0] = static_cast<int>(ii);
|
||||||
for(size_t j = 0; j <= len2; ++j)
|
for(size_t jj = 0; jj <= len2; ++jj)
|
||||||
dp[0][j] = static_cast<int>(j);
|
dp[0][jj] = static_cast<int>(jj);
|
||||||
|
|
||||||
for(size_t i = 1; i <= len1; ++i) {
|
for(size_t i = 1; i <= len1; ++i) {
|
||||||
for(size_t j = 1; j <= len2; ++j) {
|
for(size_t j = 1; j <= len2; ++j) {
|
||||||
@ -37,13 +60,22 @@ int levenshteinDistance(const std::string &s1, const std::string &s2) {
|
|||||||
return dp[len1][len2];
|
return dp[len1][len2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class MatchType:std::uint8_t {proximity,prefix};
|
||||||
|
|
||||||
// Finds the closest string from a list (modified from chat gpt code)
|
// Finds the closest string from a list (modified from chat gpt code)
|
||||||
std::pair<std::string, int> findClosestMatch(const std::string &input, const std::vector<std::string> &candidates) {
|
std::pair<std::string, int> findClosestMatch(const std::string &input, const std::vector<std::string> &candidates,MatchType match) {
|
||||||
std::string closest;
|
std::string closest;
|
||||||
int minDistance = (std::numeric_limits<int>::max)();
|
int minDistance = (std::numeric_limits<int>::max)();
|
||||||
|
int distance=minDistance;
|
||||||
for(const auto &candidate : candidates) {
|
for(const auto &candidate : candidates) {
|
||||||
int distance = levenshteinDistance(input, candidate);
|
if (match == MatchType::proximity)
|
||||||
|
{
|
||||||
|
distance = levenshteinDistance(input, candidate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
distance = prefixMatch(input, candidate);
|
||||||
|
}
|
||||||
if(distance < minDistance) {
|
if(distance < minDistance) {
|
||||||
minDistance = distance;
|
minDistance = distance;
|
||||||
closest = candidate;
|
closest = candidate;
|
||||||
@ -53,29 +85,16 @@ std::pair<std::string, int> findClosestMatch(const std::string &input, const std
|
|||||||
return {closest, minDistance};
|
return {closest, minDistance};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This example demonstrates the use of `prefix_command` on a subcommand
|
void addCloseMatchDetection(CLI::App* app, MatchType match)
|
||||||
to capture all subsequent arguments along with an alias to make it appear as a regular options.
|
{
|
||||||
|
app->allow_extras(true);
|
||||||
|
|
||||||
All the values after the "sub" or "--sub" are available in the remaining() method.
|
app->parse_complete_callback([&app,match]() {
|
||||||
*/
|
auto extras = app->remaining();
|
||||||
int main(int argc, const char *argv[]) {
|
|
||||||
|
|
||||||
int value{0};
|
|
||||||
CLI::App app{"cose string App"};
|
|
||||||
app.add_option("-v", value, "value");
|
|
||||||
|
|
||||||
app.add_subcommand("install", "");
|
|
||||||
app.add_subcommand("upgrade", "");
|
|
||||||
app.add_subcommand("remove", "");
|
|
||||||
app.add_subcommand("test", "");
|
|
||||||
app.allow_extras(true);
|
|
||||||
|
|
||||||
app.parse_complete_callback([&app]() {
|
|
||||||
auto extras = app.remaining();
|
|
||||||
if(extras.empty()) {
|
if(extras.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto subs = app.get_subcommands(nullptr);
|
auto subs = app->get_subcommands(nullptr);
|
||||||
std::vector<std::string> list;
|
std::vector<std::string> list;
|
||||||
for(const auto *sub : subs) {
|
for(const auto *sub : subs) {
|
||||||
if(!sub->get_name().empty()) {
|
if(!sub->get_name().empty()) {
|
||||||
@ -88,13 +107,28 @@ int main(int argc, const char *argv[]) {
|
|||||||
}
|
}
|
||||||
for(auto &extra : extras) {
|
for(auto &extra : extras) {
|
||||||
if(extra.front() != '-') {
|
if(extra.front() != '-') {
|
||||||
auto closest = findClosestMatch(extra, list);
|
auto closest = findClosestMatch(extra, list,match);
|
||||||
if(closest.second <= 3) {
|
if(closest.second <= 3) {
|
||||||
std::cout << "unmatched commands " << extra << ", closest match is " << closest.first << "\n";
|
std::cout << "unmatched commands " << extra << ", closest match is " << closest.first << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This example demonstrates the use of close match detection to detect invalid commands that are close matches to existing ones
|
||||||
|
*/
|
||||||
|
int main(int argc, const char *argv[]) {
|
||||||
|
|
||||||
|
int value{0};
|
||||||
|
CLI::App app{"cose string App"};
|
||||||
|
app.add_option("-v", value, "value");
|
||||||
|
|
||||||
|
app.add_subcommand("install", "");
|
||||||
|
app.add_subcommand("upgrade", "");
|
||||||
|
app.add_subcommand("remove", "");
|
||||||
|
app.add_subcommand("test", "");
|
||||||
|
addCloseMatchDetection(&app,MatchType::prefix);
|
||||||
CLI11_PARSE(app, argc, argv);
|
CLI11_PARSE(app, argc, argv);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user