export sl_did_you_mean that uses OptimalStringAlignmentDistance to propose an alternative
This commit is contained in:
84
lib/sl/sl.c
84
lib/sl/sl.c
@@ -396,3 +396,87 @@ sl_slc_help (SL_cmd *cmds, int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* OptimalStringAlignmentDistance */
|
||||||
|
|
||||||
|
static int
|
||||||
|
osad(const char *s1, const char *s2)
|
||||||
|
{
|
||||||
|
size_t l1 = strlen(s1), l2 = strlen(s2), i, j;
|
||||||
|
int *row0, *row1, *row2, *tmp, cost;
|
||||||
|
|
||||||
|
row0 = calloc(sizeof(int), l2 + 1);
|
||||||
|
row1 = calloc(sizeof(int), l2 + 1);
|
||||||
|
row2 = calloc(sizeof(int), l2 + 1);
|
||||||
|
|
||||||
|
for (j = 0; j < l2 + 1; j++)
|
||||||
|
row1[j] = j;
|
||||||
|
|
||||||
|
for (i = 0; i < l1; i++) {
|
||||||
|
|
||||||
|
row2[0] = i + 1;
|
||||||
|
|
||||||
|
for (j = 0; j < l2; j++) {
|
||||||
|
|
||||||
|
row2[j + 1] = row1[j] + (s1[i] != s2[j]); /* substitute */
|
||||||
|
|
||||||
|
if (row2[j + 1] > row1[j + 1] + 1) /* delete */
|
||||||
|
row2[j + 1] = row1[j + 1] + 1;
|
||||||
|
if (row2[j + 1] > row2[j] + 1) /* insert */
|
||||||
|
row2[j + 1] = row2[j] + 1;
|
||||||
|
if (j > 0 && i > 0 && s1[i - 1] != s2[j - 1] && s1[i - 1] == s2[j] && s1[i] == s2[j - 1] && row2[j + 1] < row0[j - 1]) /* transposition */
|
||||||
|
row2[j + 1] = row0[j - 1] + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = row0;
|
||||||
|
row0 = row1;
|
||||||
|
row1 = row2;
|
||||||
|
row2 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
cost = row1[l2];
|
||||||
|
|
||||||
|
free(row0);
|
||||||
|
free(row1);
|
||||||
|
free(row2);
|
||||||
|
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sl_did_you_mean(SL_cmd *cmds, const char *match)
|
||||||
|
{
|
||||||
|
int *metrics, best_match = INT_MAX, print = 0;
|
||||||
|
SL_cmd *c;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
for (n = 0, c = cmds; c->name; c++, n++)
|
||||||
|
;
|
||||||
|
metrics = calloc(n, sizeof(metrics[0]));
|
||||||
|
if (metrics == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (n = 0; cmds[n].name; n++) {
|
||||||
|
metrics[n] = osad(match, cmds[n].name);
|
||||||
|
if (metrics[n] < best_match)
|
||||||
|
best_match = metrics[n];
|
||||||
|
}
|
||||||
|
if (best_match == INT_MAX) {
|
||||||
|
free(metrics);
|
||||||
|
fprintf(stderr, "What kind of command is %s", match);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "%s is not a known command, did you mean:", match);
|
||||||
|
for (n = 0; cmds[n].name; n++) {
|
||||||
|
if (metrics[n] == best_match) {
|
||||||
|
fprintf(stderr, "%s %s", print ? "," : "", cmds[n].name);
|
||||||
|
print = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(stderr, ".\n");
|
||||||
|
|
||||||
|
free(metrics);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@@ -61,6 +61,8 @@ int sl_make_argv(char*, int*, char***);
|
|||||||
void sl_apropos (SL_cmd *cmd, const char *topic);
|
void sl_apropos (SL_cmd *cmd, const char *topic);
|
||||||
SL_cmd *sl_match (SL_cmd *cmds, char *cmd, int exactp);
|
SL_cmd *sl_match (SL_cmd *cmds, char *cmd, int exactp);
|
||||||
void sl_slc_help (SL_cmd *cmds, int argc, char **argv);
|
void sl_slc_help (SL_cmd *cmds, int argc, char **argv);
|
||||||
|
void sl_did_you_mean(SL_cmd *cmds, const char *match);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user