C find string in text diagonally - c

Can anyone help me to organize such function ( as a homework I manage with crossword program ):
1) I have array of strings ( kind of text file ), where
row[0] = "str1"
row[1] = "str2" and etc.
2) The length of each string is same
3) Inputted word from stdin like abcd
I need to find word abcd in text located diagonally ( from left to right doesn't really matter just need kind of algorithm ) and replace found word with zeros.
First letter can be found with strchr but how correctly go forward and replace text with zeros? Can anyone give me any clue?
SOLUTION:
Tnx for minusing by the way. I've found another solution where each diagonal line is generated into 1 simple line, then I apply strstr to it to find position of match. Knowing position of match and length of matched string enables to detect precisely position of matched cells in array of lines.
I used such code ( maybe smn will find it useful ):
/* generating left-right diagonal string str */
for( col = cols - len; col >= 0; col --, i = 0 ){
/* where len is the length of searching string */
while( ( col+i ) < cols && i < rows ){
*(str + i) = res[i][col+i];
i ++;
}
*(str + i) = '\0';
//some match seq.
}
I did for left right diagonal from left top cell ( start of first string ) to last top cell ( end of first string ). Then same procedure for left column, so resulted algorithm will cover all strings.

You probably want to have a 2-dimentonal array of characters such as
char grid[i][j]
and if your first letter is at grid[i][j] than a next point in the diagonal is at
grid[i+1][j+1]
And so on for every combination of +1 and -1

Find first letter, lets say at row[5] the letter with index 7 (so row[5][7]).
Then check if row[6][8] is the second letter; or row[4][6], or row[4][8] or row[6][6]. Proceed with third letter, probably recursevily.

Related

'highlighting' a string according to a given pattern

I have a bunch of strings such as
1245046126856123
5293812332348977
1552724141123171
7992612370048696
6912394320472896
I give the program a pattern which in this case is '123' and the expected output is
1245046126856[123]
52938[123]32348977
1552724141[123]171
79926[123]70048696
69[123]94320472896
To do this I record the indices where the pattern occurs in an array and then I make an empty array of chars and put '[' and ']' according to the indices. So far it works fine but when I have a string such as
12312312312312312123
I should get
[123][123][123][123][123]12[123]
However I cannot find a way to record the indices according to such a case. I use rabin-karp algorithm for pattern matching and the section where I calculate the indeces as to where to put the brackets is as follows
if(j == M){
index[k] = i; //beginning index
index[k+1] = i+M+1; //finishing index
if((k!=0)&&(index[k-1] == index[k])){
index[k]++;
index[k+1]++;
}
if((k!=0)&&(index[k] < index[k-1])){
index[k] = index[k-2]+M+1;
index[k+1] = i-index[k-1]+M+1;
}
k += 2;
}
i is the index where the pattern starts to occur,
j is the index where the algorithm terminates the pattern check (last character of the given pattern),
k is the index of the index array.
M is the length of the pattern
This results in a string (where only the brackets are placed) like this
[ ][ ][ ][ ][ ][ ]
but as you can see, there should be two empty spaces between the last two sets of brackets. How can I adjust way I calculate the indexes so that I can properly place the brackets?
EDIT
thought it was a python question at first so this is a pythonic answer, but it may help as a pseudo code.
this piece of code should help you find all the indexes in the string that holds the pattern.
string = "12312312312312123"
ptrn = "123"
i = 0
indexes = [] //create a dynamic array (it may also be constant size string length/pattern length or just the string length)
while True:
i = string.find(ptrn, i) //get the next index of the pattern in a substring that starts from the last index of last suffix of the pattern.
if i == -1: //if such index inside the original string (the pattern exists).
break
indexes.append(i) //add the found index of the pattern occurrence into the array.
i += len(ptrn) //get to the next position where the pattern may appear not inside another pattern.
print(indexes)
if you would like to have it on every pattern match even if it's inside another match, you can remove the i+=len(ptrn) and replace the while statement with for i in range(0,len(string)): // run for every index of the string - for(int i=0; i<strlen(string); i++)

Why is my function not deleting all numbers?

I made a function that will find any digits in an array and remove them. Here's my code:
int noNums (char *a) {
int i;
int deleteInd;
for (i = 0; (i < MAX_NAME_SZ) && (a[i] != '\0'); i++) {
if ((a[i] >= '0') && (a[i] <= '9')) {
deleteInd = i;
memmove (&a[deleteInd], &a[deleteInd + 1], strlen (a) - deleteInd);
}
}
}
If a number is by itself in the char array, then it is removed, no problem. However, if there are consecutive numbers in the array, then only every other digit will be deleted?
If my char array has
w12345678
then the array is changed to
w2468
instead of
w
Any ideas?
After you do the memmove(), the next element is now in the index of the element you just deleted. But your loop will do i++, so you won't check that index again. As a result, whenever there are two digits in a row, you skip the second one.
One way to fix this is to loop from the end of the array to the beginning, instead of from the beginning to the end.
Another way is to do i-- after doing the memmove(), to counteract the i++ that the loop will do.
if (isdigit(a[i]) {
deleteInd = i;
memmove (&a[deleteInd], &a[deleteInd + 1], strlen (a) - deleteInd);
i--;
}
BTW, you should use isdigit() to test whether a character is a digit.
Have you noticed that you are deleting the first digit then skipping one?
When iterating through the array, you start at position 0 and incrementing. When you delete a digit, you alter the string index.
i = 0 (char = w)
Index: 012345689
string: w12345678
i = 1 (char = 1)
Index: 012345689
string: w2345678
i = 2 (char = 3)
Index: 012345689
string: w2345678
Essentially, you are shifting the string over whenever you delete your character.
Don't increment i when you delete a character.
Note that deleteInd is not needed in your code, you could use i directly.
This is not an answer — Barmar's is — but both this and OP's other question shows they could use a fresh look into how to modify character arrays in place.
This is written in the hopes that this is useful to others learning C as well.
Elements, or sequences of elements, can be removed from an array efficiently, using a simple loop over its contents.
The key is to keep two indexes: one for the next element (or elements) to be examined, and one for the last element stored (or the next position to store to).
For example, to remove digits in an array, one can use the following pseudocode function:
Function removedigits(array, length):
Let i = 0 # Index of next element to examine, "input"
Let o = 0 # Position of next element to store, "output"
While (i < length):
If (array[i] is not a digit):
Let array[o] = array[i]
Let o = o + 1
End If
Let i = i + 1
End While
# For a string, we'll also want to terminate the array
# at o, because the rest of it contains garbage (old contents):
Let array[o] = '\0'
End Function
When dealing with sequences, it may be useful to keep multiple indexes. For example, to remove duplicate lines, one might use the following function:
Function removeduplicatelines(array):
Let i = 0 # Next position in the array to be examined
Let o = 0 # Next position in the array to store to
Let ostarted = 0 # Index at which the last line stored started at
# Loop over each input line:
While (array[i] != '\0'):
# Find the length of this line. It can end with a newline
# or at the end of the string. The newline is not included.
Let ilen = 0
While (array[i + ilen] != '\n' && array[i + ilen] != '\0'):
Let ilen = ilen + 1
End While
# If the already stored line is of different length
# (the +1 is for the newline, as it is not included in ilen)
# or if it does not match the input line, store input line.
If (ostarted + ilen + 1 != o || memcmp(array + ostarted, array + i, ilen) != 0):
# The lengths or content differs. Store the line.
# Copy ilen characters, starting at array[i],
# to array[o] onwards.
# Because the array parts do not overlap,
# we can safely use memcpy() here.
memcpy(array + o, array + i, ilen)
# It is now the last stored line.
Let ostarted = o
Let o = o + ilen
# If there is a newline following the line,
# store that too.
If (array[i + ilen] == '\n'):
Let array[o] = '\n'
Let o = o + 1
End If
Else:
# It is the same line again. Do not store.
End If
# Proceed to the next input line.
Let i = i + ilen
# Because the newline was not included in ilen,
# skip it if there is one.
If (array[i] == '\n'):
Let i = i + 1
End If
End While
# After index o, the array may contain old contents;
# so terminate the string at index o.
Let array[o] = '\0'
End Function
Note that memcmp() returns zero, if the ilen characters starting at array + ostarted match those starting at array + i.
This approach works, if we know o never exceeds i; that is, that we never overwrite array contents we haven't examined yet. But do note that o is allowed to be equal to i, as that just means we overwrite the same character we just examined, making no actual change in the array.
If we wanted to modify the function so that it skips empty lines, we add a new while loop before the existing one, to remove any leading newlines:
While (array[i] == '\n'):
Let i = i + 1
End While
and, to remove any empty lines, we modify the last part within the while loop into
# Because the newline was not included in ilen,
# skip it (and any additional newlines) if there is one.
While (array[i] == '\n'):
Let i = i + 1
End While
Finally, do note that the above removeduplicatelines() is very careful about not appending a newline after the last line, if there isn't one in the array to begin with.

How to split sentences in an array

I have a string s which stores a very long sentence and I want to copy the content of s to an array C with each cell storing a sentence each. The following is my code which is not giving me any output, but the dimension of the cell:
while(i<6)
C(i)=s;
end
This is how I get as output when I print C:
C=
[1x76 char]
Can somebody please help me.
Another job for strsplit:
>> sentences = 'This is the first one. Then here is a second. Yet another here.';
>> C = strsplit(sentences,'. ')
C =
'This is the first one' 'Then here is a second' 'Yet another here.'
We are specifying a period followed by a space as the delimiter. Change this as needed.
Suppose Long string is:
longString = "This is first cell. This is second cell. this is third cell".
Now since . is delimiter here means it is acting as separator for sentences. so you can loop through longString character wise and whenever you encounter a . you just increase Array index count and keep storing in this Array index until you find another .
here is sudo code:
array[];
index = 0;
loop through(longString) character wise
{
if(currentChar equals to '.')
{
index++;
}
else
{
array[index] = currentChanracter;
}
}

Shortest window in all numbers appear [duplicate]

Saw this question recently:
Given 2 arrays, the 2nd array containing some of the elements of the 1st array, return the minimum window in the 1st array which contains all the elements of the 2nd array.
Eg :
Given A={1,3,5,2,3,1} and B={1,3,2}
Output : 3 , 5 (where 3 and 5 are indices in the array A)
Even though the range 1 to 4 also contains the elements of A, the range 3 to 5 is returned Since it contains since its length is lesser than the previous range ( ( 5 - 3 ) < ( 4 - 1 ) )
I had devised a solution but I am not sure if it works correctly and also not efficient.
Give an Efficient Solution for the problem. Thanks in Advance
A simple solution of iterating through the list.
Have a left and right pointer, initially both at zero
Move the right pointer forwards until [L..R] contains all the elements (or quit if right reaches the end).
Move the left pointer forwards until [L..R] doesn't contain all the elements. See if [L-1..R] is shorter than the current best.
This is obviously linear time. You'll simply need to keep track of how many of each element of B is in the subarray for checking whether the subarray is a potential solution.
Pseudocode of this algorithm.
size = bestL = A.length;
needed = B.length-1;
found = 0; left=0; right=0;
counts = {}; //counts is a map of (number, count)
for(i in B) counts.put(i, 0);
//Increase right bound
while(right < size) {
if(!counts.contains(right)) continue;
amt = count.get(right);
count.set(right, amt+1);
if(amt == 0) found++;
if(found == needed) {
while(found == needed) {
//Increase left bound
if(counts.contains(left)) {
amt = count.get(left);
count.set(left, amt-1);
if(amt == 1) found--;
}
left++;
}
if(right - left + 2 >= bestL) continue;
bestL = right - left + 2;
bestRange = [left-1, right] //inclusive
}
}

How do I remove duplicate strings from an array in C?

I have an array of strings in C and an integer indicating how many strings are in the array.
char *strarray[MAX];
int strcount;
In this array, the highest index (where 10 is higher than 0) is the most recent item added and the lowest index is the most distant item added. The order of items within the array matters.
I need a quick way to check the array for duplicates, remove all but the highest index duplicate, and collapse the array.
For example:
strarray[0] = "Line 1";
strarray[1] = "Line 2";
strarray[2] = "Line 3";
strarray[3] = "Line 2";
strarray[4] = "Line 4";
would become:
strarray[0] = "Line 1";
strarray[1] = "Line 3";
strarray[2] = "Line 2";
strarray[3] = "Line 4";
Index 1 of the original array was removed and indexes 2, 3, and 4 slid downwards to fill the gap.
I have one idea of how to do it. It is untested and I am currently attempting to code it but just from my faint understanding, I am sure this is a horrendous algorithm.
The algorithm presented below would be ran every time a new string is added to the strarray.
For the interest of showing that I am trying, I will include my proposed algorithm below:
Search entire strarray for match to str
If no match, do nothing
If match found, put str in strarray
Now we have a strarray with a max of 1 duplicate entry
Add highest index strarray string to lowest index of temporary string array
Continue downwards into strarray and check each element
If duplicate found, skip it
If not, add it to the next highest index of the temporary string array
Reverse temporary string array and copy to strarray
Once again, this is untested (I am currently implementing it now). I just hope someone out there will have a much better solution.
The order of items is important and the code must utilize the C language (not C++). The lowest index duplicates should be removed and the single highest index kept.
Thank you!
The typical efficient unique function is to:
Sort the given array.
Verify that consecutive runs of the same item are setup so that only one remains.
I believe you can use qsort in combination with strcmp to accomplish the first part; writing an efficient remove would be all on you though.
Unfortunately I don't have specific ideas here; this is kind of a grey area for me because I'm usually using C++, where this would be a simple:
std::vector<std::string> src;
std::sort(src.begin(), src.end());
src.remove(std::unique(src.begin(), src.end()), src.end);
I know you can't use C++, but the implementation should essentially be the same.
Because you need to save the original order, you can have something like:
typedef struct
{
int originalPosition;
char * string;
} tempUniqueEntry;
Do your first sort with respect to string, remove unique sets of elements on the sorted set, then resort with respect to originalPosition. This way you still get O(n lg n) performance, yet you don't lose the original order.
EDIT2:
Simple C implementation example of std::unique:
tempUniqueEntry* unique ( tempUniqueEntry * first, tempUniqueEntry * last )
{
tempUniqueEntry *result=first;
while (++first != last)
{
if (strcmp(result->string,first->string))
*(++result)=*first;
}
return ++result;
}
I don't quite understand your proposed algorithm (I don't understand what it means to add a string to an index in step 5), but what I would do is:
unsigned int i;
for (i = n; i > 0; i--)
{
unsigned int j;
if (strarray[i - 1] == NULL)
{
continue;
}
for (j = i - 1; j > 0; j--)
{
if (strcmp(strarray[i - 1], strarray[j - 1]) == 0)
{
strarray[j - 1] = NULL;
}
}
}
Then you just need to filter the null pointers out of your array (which I'll leave as an exercise).
A different approach would be to iterate backwards over the array and to insert each item into a (balanced) binary search tree as you go. If the item is already in the binary search tree, flag the array item (such as setting the array element to NULL) and move on. When you've processed the entire array, filter out the flagged elements as before. This would have slightly more overhead and would consume more space, but its running time would be O(n log n) instead of O(n^2).
Can you control the input as it is going into the array? If so, just do something like this:
int addToArray(const char * toadd, char * strarray[], int strcount)
{
const int toaddlen = strlen(toadd);
// Add new string to end.
// Remember to add one for the \0 terminator.
strarray[strcount] = malloc(sizeof(char) * (toaddlen + 1));
strncpy(strarray[strcount], toadd, toaddlen + 1);
// Search for a duplicate.
// Note that we are cutting the new array short by one.
for(int i = 0; i < strcount; ++i)
{
if (strncmp(strarray[i], toaddlen + 1) == 0)
{
// Found duplicate.
// Remove it and compact.
// Note use of new array size here.
free(strarray[i]);
for(int k = i + 1; k < strcount + 1; ++k)
strarray[i] = strarray[k];
strarray[strcount] = null;
return strcount;
}
}
// No duplicate found.
return (strcount + 1);
}
You can always use the above function looping over the elements of an existing array, building a new array without duplicates.
PS: If you are doing this type of operation a lot, you should move away from an array as your storage structure, and used a linked list instead. They are much more efficient for removing elements from a location other than the end.
Sort the array with an algorithm like qsort (man 3 qsort in the terminal to see how it should be used) and then use the function strcmp to compare the strings and find duplicates
If you want to mantain the original order you could use a O(N^2) complexity algorithm nesting two for, the first each time pick an element to compare to the other and the second for will be used to scan the rest of the array to find if the chosen element is a duplicate.

Resources