I'm currently working on the CS50 Speller function. I have managed to compile my code and have finished a prototype of the full program, however it does not work (it doesn't recognise any mispelled words). I am looking through my functions one at a time and printing out their output to have a look at what's going on inside.
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
char word[LENGTH + 1];
int counter = 0;
FILE *dicptr = fopen(dictionary, "r");
if (dicptr == NULL)
{
printf("Could not open file\n");
return 1;
}
while (fscanf(dicptr, "%s", word) != EOF)
{
printf("%s", word);
node *n = malloc(sizeof(node));
if (n == NULL)
{
unload();
printf("Memory Error\n");
return false;
}
strcpy(n->word, word);
int h = hash(n->word);
n->next = table[h];
table[h] = n;
amount++;
}
fclose(dicptr);
return true;
}
From what I can see this works fine. Which makes me wonder if the issue is with my check function as shown here:
bool check(const char *word)
{
int n = strlen(word);
char copy[n + 1];
copy[n] = '\0';
for(int i = 0; i < n; i++)
{
copy[i] = tolower(word[i]);
printf("%c", copy[i]);
}
printf("\n");
node *cursor = table[hash(copy)];
while(cursor != NULL)
{
if(strcasecmp(cursor->word, word))
{
return true;
}
cursor = cursor->next;
}
return false;
}
If someone with a keener eye can spy what is the issue I'd be very grateful as I'm stumped. The first function is used to load a the words from a dictionary into a hash table\linked list. The second function is supposed to check the words of a txt file to see if they match with any of the terms in the linked list. If not then they should be counted as incorrect.
This if(strcasecmp(cursor->word, word)) is a problem. From man strcasecmp:
Return Value
The strcasecmp() and strncasecmp() functions return an
integer less than, equal to, or greater than zero if s1 (or the first
n bytes thereof) is found, respectively, to be less than, to match, or
be greater than s2.
If the words match, it returns 0, which evaluates to false.
Related
This question is an extension of another question:
TEdit Input Validation on C++ Builder XE8
I have an editable TStringGrid. I only want the user to type numbers and a maximum of one decimal point or comma for each cell in the grid.
From the above link, I understand how to permit only certain keys, but not how to keep track of how many times a certain key-value already exists in the given cell.
From the above link, I have this:
void __fastcall TSetDataForm::ProbabilityGridKeyPress(TObject *Sender, System::WideChar &Key)
{
if( Key == VK_BACK )
return;
if( (Key < L'0') || (Key > L'9') )
{
ShowMessage("Please enter numerals only");
Key = 0;
}
}
How do I allow '.' or ',' but only once?
I would suggest using TryStrToFloat() to validate the input, then there is no question whether the user is entering a valid decimal string or not. You would just need to handle the extra cases where:
the user is typing a character somewhere other than the end of the edit field, with or without text selected.
the user is copy/pasting text into the editor.
For example:
class TStringGridAccess : public TStringGrid
{
public:
__property InplaceEditor;
};
void __fastcall TSetDataForm::ProbabilityGridKeyPress(TObject *Sender, System::WideChar &Key)
{
switch (Key)
{
case 3: // Ctrl-C
case 8: // Backspace
return;
case 22: // Ctrl-V
{
Key = 0;
TInplaceEdit *Editor = ((TStringGridAccess*)ProbabilityGrid)->InplaceEditor;
String SaveCellText = ProbabilityGrid->Cells[ProbabilityGrid->Col][ProbabilityGrid->Row];
String SaveEditText = Editor->Text;
int SaveSelStart = Editor->SelStart;
int SaveSelLen = Editor->SelLength;
Editor->Perform(WM_PASTE, 0, 0);
TFormatSettings fmt = TFormatSettings::Create();
fmt.DecimalSeparator = _D('.');
double value;
if (TryStrToFloat(Editor->Text, value, fmt))
return;
ProbabilityGrid->Cells[ProbabilityGrid->Col][ProbabilityGrid->Row] = SaveCellText;
Editor->Text = SaveEditText;
Editor->SelStart = SaveSelStart;
Editor->SelLength = SaveSelLen;
break;
}
case _D('0'):
case _D('1'):
case _D('2'):
case _D('3'):
case _D('4'):
case _D('5'):
case _D('6'):
case _D('7'):
case _D('8'):
case _D('9'):
case _D('.'):
{
TInplaceEdit *Editor = ((TStringGridAccess*)ProbabilityGrid)->InplaceEditor;
String str = Editor->Text;
int idx = Editor->SelStart;
int len = Editor->SelLength;
String str2 = str.SubString(1, idx) + Key + str.SubString(1+idx+len, MaxInt);
TFormatSettings fmt = TFormatSettings::Create();
fmt.DecimalSeparator = _D('.');
double value;
if (TryStrToFloat(str2, value, fmt))
return;
break;
}
}
ShowMessage(_D("Please enter decimals only"));
Key = 0;
}
My problem was stemming from the fact that I did not know how to read the text of the cell that the user is writing in.
Here is my solution for anyone interested:
void __fastcall TSetDataForm::ProbabilityGridKeyPress(TObject *Sender, System::WideChar &Key)
{
if( Key == VK_BACK )
return;
if( !((Key >= L'0') && (Key <= L'9') || (Key == L'.')))
{
ShowMessage("Please enter numerals only");
Key = 0;
}
else if ((Key == L'.') &&
(Pos(Key, ProbabilityGrid->Cells[ProbabilityGrid->Col][ProbabilityGrid->Row]) > 0))
{
ShowMessage("Two dots!");
Key = 0;
}
}
My pointer is declared in the header file:
int (*array)[10];
I pass a argument to a function that initializes the array:
void __fastcall TForm1::Initarray(const int cnt)
{
try
{
Form1->array = new int[cnt][53];
}
catch(bad_alloc xa)
{
Application->MessageBoxA("Memory allocation error SEL. ", MB_OK);
}
Form1->Zeroarray();
}
//---------------------------------------------------------------------------
I set all element of the array to "0":
void __fastcall TForm1::Zeroarray()
{
__int16 cnt = SIZEOF_ARRAY(array);
// Here is where I notice the problem. cnt is not correct for the size of the first level of the array.
if(cnt)
{
for(int n = 0; n < cnt; n++)
{
for(int x = 0; x < 53; x++)
{
Form1->array[n][x] = 0;
}
}
}
}
//---------------------------------------------------------------------------
This is my defined size of array macro:
#define SIZEOF_ARRAY(a) (sizeof((a))/sizeof((a[0])));
When array is created with 10 elements of 53 elements array[10][53]
I get a return from SIZEOF_ARRAY == 0. It should equal 10.
I have tried several variation of this macro and just doing straight math with the sizeof() but I cannot get the correct output.
What am I not doing?
I need to write a Groovy function to check if two given strings match at least 90%. I just wanted to know if anyone knew of an already existent such utility method that I could use in a Grails project. I haven't really written the method yet but ideally this is how it would work:
def doStringsMatch(String str1, String str2) {
if (str1 and str2 match at least 90% or
str1 appears in str2 somewhere or
str2 appears in str1 somewhere)
return true
else
return false
}
Thanks
This is a groovy implementation of Levenshtein distance, basically it returns a percentage of how similar the two strings appear to be. 0 means they are completely different and 1 means they are the exact same. This implementation is case insensitive.
private double similarity(String s1, String s2) {
if (s1.length() < s2.length()) { // s1 should always be bigger
String swap = s1; s1 = s2; s2 = swap;
}
int bigLen = s1.length();
if (bigLen == 0) { return 1.0; /* both strings are zero length */ }
return (bigLen - computeEditDistance(s1, s2)) / (double) bigLen;
}
private int computeEditDistance(String s1, String s2) {
s1 = s1.toLowerCase();
s2 = s2.toLowerCase();
int[] costs = new int[s2.length() + 1];
for (int i = 0; i <= s1.length(); i++) {
int lastValue = i;
for (int j = 0; j <= s2.length(); j++) {
if (i == 0)
costs[j] = j;
else {
if (j > 0) {
int newValue = costs[j - 1];
if (s1.charAt(i - 1) != s2.charAt(j - 1))
newValue = Math.min(Math.min(newValue, lastValue),
costs[j]) + 1;
costs[j - 1] = lastValue;
lastValue = newValue;
}
}
}
if (i > 0)
costs[s2.length()] = lastValue;
}
return costs[s2.length()];
}
I have a file format something like this
...
{string_length} {binary_string}
...
example:
...
10 abcdefghij
...
Is this possible to parse using lexer/yacc? There is no null terminator for the string, so I'm at a loss of how to tokenize that.
I'm currently using ply's lexer and yacc for this
You can't do it with a regular expression, but you can certainly extract the lexeme. You're not specific about how the length is terminated; here, I'm assuming that it is terminated by a single space character. I'm also assuming that yylval has some appropriate struct type:
[[:digit:]]+" " { unsigned long len = atol(yytext);
yylval.str = malloc(len);
yylval.len = len;
for (char *p = yylval.str; len; --len, ++p) {
int ch = input();
if (ch == EOF) { /* handle the lexical error */ }
*p = ch;
}
return BINARY_STRING;
}
There are other solutions (a start condition and a state variable for the count, for example), but I think the above is the simplest.
I would like to parse some input, mainly numbers, that can be delimited using underscore ( _ ) for user readability.
Ex.
1_0001_000 -> 1000100
000_000_111 -> 000000111
How would I set up my flex/yacc to do so?
Here's a potential flex answer (in C):
DIGIT [0-9]
%%
{DIGIT}+("_"{DIGIT}+)* { int numUnderscores = 0;
for(int i = 0; i < yyleng; i++)
if(yytext[i] == '_')
numUnderscores++;
int stringLength = yyleng - numUnderscores + 1;
char *string = (char*) malloc(sizeof(char) * stringLength);
/* be sure to check and ensure string isn't NULL */
int pos = 0;
for(int i = 0; i < yyleng; i++) {
if(yytext[i] != '_') {
string[pos] = yytext[i];
pos++;
}
}
return string;
}
If you know the maximum size of the number, you could use a statically sized array instead of dynamically allocating space for the string.
As stated before flex isn't the most efficient tool for solving this problem. If this problem is part of a larger problem (such as a language grammar), then keep using flex. Otherwise, there are many more efficient ways of handling this.
If you just need the string numerically, try this:
DIGIT [0-9]
%%
{DIGIT}+("_"{DIGIT}+)* { int number = 0;
for(int i = 0; i < yyleng; i++)
if(yytext[i] != '_')
number = (number*10) + (yytext[i]-'0');
return number;
}
Just be sure to check for overflow!