View Full Version : [C] Parola più lunga da stringa
Ciao a tutti!
Devo scrivere un programma in c in grado di predendere in input una stringa di testo ( massimo 132 caratteri ), leggerla, e stampare a schermo la parola più lunga presente nella stringa.
Nel caso in cui ci fossero due o più parole con la stessa massima lunghezza, il programma deve stamparle.
Per ora ho scritto questo:
/*
Write a C program that reads a line of text from keyboard and then writes the longest word in the line.
If more than one word has longest length, the program will output all of them.
The program should work with lines up to 132 characters long and ignore characters in excess.
*/
#include <stdio.h>
#include <string.h>
#define MAX 133
int get_line ( char str_line[MAX] );
void erase_array ( char array[MAX]);
void search_in_string ( char str_line[MAX], int str_len);
int main (void)
{
int get_line_result=0; //This gets the lenght of the array and checks if there's any error
char str_line[MAX];
erase_array( str_line );
printf("Insert a line of text\n");
printf("The line cannot exceed 132 characters\n");
if ((get_line_result = get_line ( str_line )) == -1)
{
printf("Error in reading the line");
return -1;
}
else
{
search_in_string ( str_line, get_line_result );
}
return 0;
}
void erase_array (char array[MAX])
{
int i;
for ( i=0; i < MAX; i++ )
array=0;
}
int get_line ( char str_line[MAX] )
{
int max_str_lenght = MAX - 1; //We reserve the last slot for \0
int i=0;
if ( fgets( str_line, max_str_lenght, stdin)== NULL )
return -1;
else
i = strlen(str_line);
printf("Array has lenght: %d\n", i-1); // i-1 because it counts also \0 and we don't want this
return i-1;
}
void search_in_string ( char str_line[MAX], int str_len)
{
int i=0, temp=-1; //Indexes
char word[MAX];
char longest_word[MAX];
int max_len=0;
erase_array( word );
erase_array( longest_word );
do
{
for ( i= temp ; str_line[i] != ' '; i++)
;
temp = i + 1;
strncpy (word, str_line, i+1);
max_len = i;
}while ( str_line[i] != '\n' || str_line[i] !='\0');
}
Come si vede dal codice, faccio uso di due array:
- Il primo che contiene tutta la stringa
- Il secondo che dovrà contenere tutti le parole di massima lunghezza.
Quello che non riesco a fare è dire al programma, memorizzata la prima parola nel vettore ( che ovviamente, essendo la prima, sarà certamente la più lunga di quelle fino ad ora controllate ) di riprendere il vettore stringa, escludere la prima parola, e passare a quella successiva.
Penso che questo non sia il modo corretto di operare ( e nemmeno il più semplice ) ma l'unica altra idea che mi è venuta in mente è stata quella di fare così:
Leggo la stringa
Ad ogni spazio mi fermo e guardo quanto è lunga la parola
Memorizzo da qualche parte le lunghezze di ogni singola parola
Se ci sono delle lunghezze uguali uso la funzione per concatenare le stringhe, altrimenti copio solo n caratteri con [I]strncpy.
Memorizzo le/la parole/a nel vettore apposito
Stampo il vettore
Mi sembra possa funzionare, però non ho idea di come:
Memorizzare tutte le lunghezze: dovrei creare un vettore di non si sa che dimensione...
Tornare nel vettore stringa a prendere le singole parole per metterle nel vettore che stamperò...
Penso di essermi perso in un bicchier d'acqua perchè sono sicuro ci sia una soluzione molto più semplice... Ma non mi viene in mente niente altro di meglio...
Vorrei cercare di capire come fare più che avere il codice fatto. Ovvio, non mi offendo se mettete piccole righe di codice... :D
è molto più semplice (ma di complessità equivalente) prima cercare quale sia la lunghezza massima e poi stampare quelle che hanno quella lunghezza
per semplificarti la vita potresti, nella prima "passata", sostituire gli spazi con '\0', così da poter usare puts e strlen
memorizzare la dimenisone di ogni singola parola può essere un'ottimizzazione valida anche procedendo come ho descritto, puoi farlo usando realloc
aggiungendo prima di tutto:
int *len_v = NULL, size = 0;
e poi, dopo aver calcolato la lunghezza di una parola:
len_v = realloc(len_v, sizeof(int) * (++size));
len_v[size-1] = /* LUNGHEZZA */;
banalissimo:
#include <iostream>
#include <string>
using namespace std;
int main() {
string strLongestWord;
while (!cin.eof()) {
string strWord;
cin >> strWord;
if (strWord.length() > strLongestWord.length()) {
strLongestWord = strWord;
}
}
cout << strLongestWord << endl;
return 0;
}
:Prrr:
DanieleC88
05-07-2010, 19:38
banalissimo:
#include <iostream>
#include <string>
using namespace std;
int main() {
string strLongestWord;
while (!cin.eof()) {
string strWord;
cin >> strWord;
if (strWord.length() > strLongestWord.length()) {
strLongestWord = strWord;
}
}
cout << strLongestWord << endl;
return 0;
}
:Prrr:
Non funziona se ci sono più parole della stessa lunghezza (massima). :Prrr:
@kwb: usa strtok() se vuoi restare sul C, altrimenti usa C++ e campa felice.
E' un esercizio, non credo che possa usare C++ ;)
Se vuoi fare in due passaggi:
- trovi la lunghezza massima
- riparti da capo e trovi tutte le parole di lunghezza pari a quella massima e le stampi direttamente
Se vuoi fare in un solo passaggio:
- ti serve un vettore di interi contenente la posizione delle parole più lunghe, un intero che ti dice quante posizioni sono valide nel vettore precedente, un intero che ti indica la lunghezza massima
- se trovi una parola più lunga della lunghezza massima già trovata (inizializzata a 0), metti ad uno il contatore delle posizioni e inserisci la posizione nel vettore
- se trovi una parola lunga uguale alla lunghezza massima, incrementi il contatore e inserisci al posizione in cui si trova nel vettore.
Alla fine avrai la lunghezza massima e le posizioni all'interno del vettore in cui si trovano le parole di lunghezza massima.
A questo punto ci sono modi furbi per stamparle e modi meno furbi, lascio a te l'onere di trovare il modo più furbo.
PS: usare strtok è un po' difficile in questo caso. Una parola è una sequenza di caratteri alfabetici, quindi andrebbero inserite in strtok tutte i caratteri diversi da quelli alfabetici. Imho ti conviene di più usare una scansione carattere per carattere. La parola inizia appena trovi un carattere alfabetico (isalpha in C standard) e termina quanto trovi un carattere diverso.
è molto più semplice (ma di complessità equivalente) prima cercare quale sia la lunghezza massima e poi stampare quelle che hanno quella lunghezza
per semplificarti la vita potresti, nella prima "passata", sostituire gli spazi con '\0', così da poter usare puts e strlen
memorizzare la dimenisone di ogni singola parola può essere un'ottimizzazione valida anche procedendo come ho descritto, puoi farlo usando realloc
aggiungendo prima di tutto:
int *len_v = NULL, size = 0;
e poi, dopo aver calcolato la lunghezza di una parola:
len_v = realloc(len_v, sizeof(int) * (++size));
len_v[size-1] = /* LUNGHEZZA */;
Il fatto è che quando ci sono stati assegnati questi esercizi la storia dell'allocazione della memoria non era stata ancora spiegata, quindi non ne potevamo fare uso.
banalissimo:
#include <iostream>
#include <string>
using namespace std;
int main() {
string strLongestWord;
while (!cin.eof()) {
string strWord;
cin >> strWord;
if (strWord.length() > strLongestWord.length()) {
strLongestWord = strWord;
}
}
cout << strLongestWord << endl;
return 0;
}
:Prrr: Ma non ho la più pallida idea di cosa faccia questa cosa... Ma è C? :D
Non funziona se ci sono più parole della stessa lunghezza (massima). :Prrr:
@kwb: usa strtok() se vuoi restare sul C, altrimenti usa C++ e campa felice.
Uhmm... Ho provato a leggere sui manuali e a capire cosa faccia questa funzione, ma non mi è molto chiaro, mi spiegate?
DanieleC88
05-07-2010, 20:31
PS: usare strtok è un po' difficile in questo caso. Una parola è una sequenza di caratteri alfabetici, quindi andrebbero inserite in strtok tutte i caratteri diversi da quelli alfabetici. Imho ti conviene di più usare una scansione carattere per carattere. La parola inizia appena trovi un carattere alfabetico (isalpha in C standard) e termina quanto trovi un carattere diverso.
Sinceramente non penso che l'esercizio si spinga fino a questo punto, credo voglia un semplice programma che spezza le parole in base agli spazi. Però ci servirebbe una conferma o smentita da kwb.
@kwb: se usi Linux o un altro sistema Unix-like puoi dare man 3 strtok per leggere la documentazione di strtok(). Qui (http://it.wikipedia.org/wiki/Strtok) ci sono alcuni esempi (e non capisco perché un'enciclopedia dovrebbe mai interessarsene, comunque).
DanieleC88
05-07-2010, 20:51
Faccio io un esempio veloce, va', che forse è meglio.
La funzione strtok() serve a spezzare una stringa composta da più sottostringhe (token) intervallate da alcuni caratteri particolari (delimitatori).
Se hai una stringa di questo tipo:
char *s ="a ab abc abcd abcde";
vedi subito che è una stringa formata da alcune sottostringhe alfabetiche, intervallate a spazi.
La funzione strtok() riceve in input il puntatore alla stringa da esaminare e il puntatore ad una stringa che contiene tutti i delimitatori. Banalmente, la funzione parte dall'inizio della stringa e va avanti finché non incontra un delimitatore (o finché non finisce la stringa, vabbe'). Quando viene trovato un delimitatore, questo viene sostituito col carattere '\0' (quindi strtok() modifica la stringa!) e viene restituito il puntatore all'inizio della stringa. Le successive chiamate non hanno bisogno del primo parametro (che dovrà essere NULL), e partiranno dal prossimo carattere non esaminato, continuando allo stesso modo finché non si incontra un delimitatore o la fine della stringa. Al termine della stringa viene restituito un NULL.
Per esempio, per la stringa precedente sulla chiamata strtok(s, " ") avresti queste modifiche:
s ="a ab abc abcd abcde";
/* prima chiamata, viene restituito &s[0] */
s ="a\0ab abc abcd abcde";
/* seconda chiamata, viene restituito &s[2] */
s ="a\0ab\0abc abcd abcde";
/* terza chiamata, viene restituito &s[5] */
s ="a\0ab\0abc\0abcd abcde";
/* quarta chiamata, viene restituito &s[9] */
s ="a\0ab\0abc\0abcd\0abcde";
/* quinta chiamata, viene restituito &s[14] */
s ="a\0ab\0abc\0abcd\0abcde";
/* sesta chiamata, viene restituito NULL */
s ="a\0ab\0abc\0abcd\0abcde";
Una velocissima implementazione potrebbe essere:
char *strtok(char *str, const char *delim)
{
static char *ptr = NULL;
char *start;
if (str != NULL) {
ptr = str;
}
for (start = ptr; *ptr != '\0'; ++ptr) {
if (strchr(delim, *ptr) != NULL)) {
*ptr++ = '\0';
return start;
}
}
return NULL;
}
L'ho scritta sul momento senza testarla, quindi prendila con le pinze. Per di più l'ho scritta di fretta, perché sto andando a mangiare. :Prrr:
ciao ;)
Sinceramente non penso che l'esercizio si spinga fino a questo punto, credo voglia un semplice programma che spezza le parole in base agli spazi. Però ci servirebbe una conferma o smentita da kwb.
Imho per uno non avvezzo ai puntatori è più semplice usare una scansione carattere per carattere che strtok ;)
Tra l'altro la realizzazione è semplicissima...
Voglio provare ad implementare il suggerimento di tuccio` , mi sembra il più semplice...
Se non va passerò a quello di cionci, che magari l'utilizzo di queste funzioni ( isAlpha ecc... ) può sempre tornare utile!
Vi faccio sapere!
realloc però non importa che tu la usi, il numero di parole non può essere maggiore di MAX / 2 ;)
isAlpha non è un'alternativa all'algoritmo, serve per limitare i caratteri che appartengono alla parola...
if(isalpha(c[i]))
equivale a
if((c[i] >= 'A' && c[i] <= 'Z') || (c[i] >= 'a' && c[i] <= 'z'))
Quindi scorrendo la stringa, la prima volta che isalpha è vero la parola è iniziata, la prima volta in cui diventa falso la parola è finita.
Con lo spazio sarebbe: la prima volta che il carattere non è un spazio la parola è inziata, la prima volta in cui trovo uno spazio la parola è finita.
Cambia solo il modo in cui una parola è delimitata, l'algoritmo è lo stesso.
Si ma adesso sto cercando di implementare il tuo metodo usando isalpha perchè con quello di sostituire gli ' ' con '\0' si creano casini nell'array...
Per ora sono riuscito a determinare la lunghezza massima nella stringa ( la lunghezza della parola più lunga insomma ).
Domani mi metto a scrivere l'ultima parte di codice per stampare la relativa parola.
Si ma adesso sto cercando di implementare il tuo metodo usando isalpha perchè con quello di sostituire gli ' ' con '\0' si creano casini nell'array...
Non sono comunque alternativi, quello quello che ti volevo far capire era questo. E' solo un modo diverso per considerare la parola. Se sostituisci '\0' ad ogni lettera che ritorna isalpha falso, l'algoritmo è perfettamente identico ;)
Non sono comunque alternativi, quello quello che ti volevo far capire era questo. E' solo un modo diverso per considerare la parola. Se sostituisci '\0' ad ogni lettera che ritorna isalpha falso, l'algoritmo è perfettamente identico ;)
Il fatto è che sostituendo ' ' con '\0' succede questo:
Stringa inserita: "Ciao oggi è nuvoloso"
Parte la funzione
1° giro: "Ciao\0"
2° giro: "Ciao\0"
ecc.. così fino a non so quando...
E' chiaro che tu debba ricominciare a considerare la stringa dal carattere successivo allo \0 e non dall'inizio ;)
E' chiaro che tu debba ricominciare a considerare la stringa dal carattere successivo allo \0 e non dall'inizio ;)
Allora... Sono riuscito a scrivere il codice completo questo è:
/*
Write a C program that reads a line of text from keyboard and then writes the longest word in the line.
If more than one word has longest length, the program will output all of them.
The program should work with lines up to 132 characters long and ignore characters in excess.
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX 133
int get_line ( char str_line[MAX] );
void erase_array ( char array[MAX]);
int longest_word ( char str_line[MAX], int str_len);
void get_word ( char str_line[MAX], char word[MAX], int max_lenght, int str_len);
int main (void)
{
int string_lenght=0; //This gets the lenght of the array and checks if there's any error
char str_line[MAX];
char word[MAX];
int max_lenght=0;
erase_array( str_line );
printf("Insert a line of text\n");
printf("The line cannot exceed 132 characters\n");
if ((string_lenght = get_line ( str_line )) == -1)
{
printf("Error in reading the line");
return -1;
}
else
{
max_lenght = longest_word ( str_line, string_lenght );
printf("The logest word has %d characters\n", max_lenght);
get_word ( str_line, word, max_lenght, string_lenght);
printf("and it is: ");
puts(word);
}
return 0;
}
void erase_array (char array[MAX])
{
int i;
for ( i=0; i < MAX; i++ )
array[i]=0;
}
int get_line ( char str_line[MAX] )
{
int max_str_lenght = MAX - 1; //We reserve the last slot for \0
int i=0;
if ( fgets( str_line, max_str_lenght, stdin)== NULL )
return -1;
else
i = strlen(str_line);
printf("Array has lenght: %d\n", i-1); // i-1 because it counts also \0 and we don't want this
return i-1;
}
int longest_word ( char str_line[MAX], int str_len)
{
int i=0;
int temp_len=0; //Stores temporary lenght
int max_len=0; //Stores maximum lenght
for ( i=0; i < str_len; i++)
{ temp_len = 0;
while ( str_line[i] != ' ' && str_line[i] != '\0' && str_line[i] != '\n')
{
if ( isalpha(str_line[i]) )
{
temp_len++;
i++;
}
}
if ( temp_len >= max_len )
max_len = temp_len;
}
return max_len;
}
void get_word ( char str_line[MAX], char word[MAX], int max_lenght, int str_len)
{
int i, temp_i=0, j, temp_j=0;
int temp_len=0;
int flag=0; //Checks if vector word has been ever filled
erase_array(word);
while( str_line[i] != '\n' && str_line[i] !='\0')
{ for ( i=temp_i; i < str_len && isalpha(str_line[i]); i++)
{
temp_len++;
}
if ( temp_len == max_lenght && flag == 0)
{ i -= max_lenght;
for(j=0; j< max_lenght; j++)
{
word[j] = str_line[i];
i++;
}
flag = 1;
temp_j= j;
word[j+1] = ' ';
}
else if ( temp_len == max_lenght && flag == 1)
{
temp_j += 2;
i -= max_lenght;
for ( j = 0; j < max_lenght; j++, temp_j++, i++)
{
word[temp_j] = str_line[i];
}
}
temp_len = 0;
temp_i = i;
temp_i++;
}
}
Tuttavia, se come stringa di input do:
"Programmo i programmi"
Il programma ( :D ) riesce a prendere correttamente la parola 'programmo' e la mette nell'array word.
Poi salta 'i' e passa a 'programmi'.
Qua però, viene eseguito il codice per caricare la parola dentro il vettore, facendo attenzione a non sovrascrivere quella esistente, però non viene caricato nulla e l'array sembra inalterabile....
Perchè?
( La parte in rosso quella incriminata )
Nessuno?
Se può servire, il problema sta in word[j+1] = ' ';
Non si sa perchè non aggiunge nulla... Ho provato pure con un carattere, ma niente...
Non mi torna questo:
int longest_word ( char str_line[MAX], int str_len)
{
int i=0;
int temp_len=0; //Stores temporary lenght
int max_len=0; //Stores maximum lenght
for ( i=0; i < str_len; i++)
{ temp_len = 0;
while ( str_line[i] != ' ' && str_line[i] != '\0' && str_line[i] != '\n')
{
if ( isalpha(str_line[i]) )
{
temp_len++;
i++;
}
}
if ( temp_len >= max_len )
max_len = temp_len;
}
return max_len;
}
Non mi torna quel controllo, non serve a molto.
Basta che controlli che i sia minore di str_len e che isalpha sia vero per il carattere corrente.
Consiglio: estraiti una funzione che dato un punto di partenza cerca l'inizio e la fine della parola corrente.
La utilizzeresti in entrambe le funzioni. Scrivila così vediamo se permette di chiarirti un po' le idee ;)
Ma che mi serve trovare l'inizio e la fine di una parola ( parliamo di indici del vettore, come inizio e fine, giusto?).
Quello che ho tentato di fare è usare la funzione strncat per accodare al vettore word n caratteri del vettore str_line... Il fatto è che con questa funzione non si può dire da che indice del vettore partire...
Ma che mi serve trovare l'inizio e la fine di una parola ( parliamo di indici del vettore, come inizio e fine, giusto?).
Quello che ho tentato di fare è usare la funzione strncat per accodare al vettore word n caratteri del vettore str_line... Il fatto è che con questa funzione non si può dire da che indice del vettore partire...
Parliamo di indici del vettore, sì.
Devi usare l'aritmetica dei puntatori o l'operatore &.
Se io voglio copiare 10 caratteri dal carattere s[5]:
strncat(dest, &s[5], 10);
oppure
strncat(dest, s + 5, 10);
Comunque fai quello che ti ho detto e vedrai che potrai utilizzare la stessa funzione in entrambe le funzioni che devi fare.
Scusami un attimo, qua mi sto perdendo...
Allora sto cercando di fare un dannato passaggio per riferimento dal main ad una funzione secondaria...
Ho scritto così ( non è uguale il codice perchè ho pasticciato e non c'ho voglia di aggiustarlo :D ):
int chiama_funzione( int *n);
main ()
{
int n=0;
chiama_funzione ( &n );
}
int chiama_funzione( int *n)
{
*n++;
}
Perchè diavolo aumenta di uno l'indirizzo e non il valore??
Come cacchio devo fare???
Sta cosa mi fa imbestialire perchè è una baggianata, mi pare di aver fatto così con altri programmi e ha sempre funzionato, qua no invece...
Non cambia nulla se metto n++ invece di *n++ ....
Quello che cercavo di fare era avere il valore di quante parole hanno la lunghezza massima. Siccome col return passo già la lunghezza massima, volevo fare un passaggio per riferimento alla funzione così da poter modificare il valore nel main.
(*n)++
Grazie grandissimo... Sapevo che era una vaccata...
Alla fine sono riuscito a venirne a capo.
Il suggerimento di cionci di saltare ad un indice x di un array tramite gli indirizzi è stato provvidenziale.
/*
Write a C program that reads a line of text from keyboard and then writes the longest word in the line.
If more than one word has longest length, the program will output all of them.
The program should work with lines up to 132 characters long and ignore characters in excess.
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX 133
int get_line ( char str_line[MAX] );
void erase_array ( char array[MAX]);
int longest_word ( char str_line[MAX], int str_len, int *n);
void get_word ( char str_line[MAX], char word[MAX], int max_lenght, int str_len, int *actual_index, int *flag);
int main (void)
{
int string_lenght=0; //This gets the lenght of the array and checks if there's any error
char str_line[MAX];
char word[MAX];
int max_lenght=0;
int n=0; //How many words has the max len?
int i=0;
int actual_index=0;//Stores the position reached by the get_word function in analyzing words
int flag=0; //Checks if word has been filled
erase_array( str_line );
printf("Insert a line of text\n");
printf("The line cannot exceed 132 characters\n");
if ((string_lenght = get_line ( str_line )) == -1)
{
printf("Error in reading the line or line is empty");
return -1;
}
else
{
max_lenght = longest_word ( str_line, string_lenght, &n );
if ( n > 1)
{
printf("There are %d words with maximum lenght of %d\n", n, max_lenght);
do
{
get_word ( str_line, word, max_lenght, string_lenght, &actual_index, &flag);
if ( flag == 1)
{
puts(word);
printf("\n");
i++;
}
} while ( i < n );
}
else {
printf("The longest word has %d characters\n", max_lenght);
while ( flag == 0)
{
get_word( str_line, word, max_lenght, string_lenght, &actual_index, &flag);
if ( flag == 1)
{
puts(word);
}
}
}
}
return 0;
}
void erase_array (char array[MAX])
{
int i;
for ( i=0; i < MAX; i++ )
array[i]=0;
}
int get_line ( char str_line[MAX] )
{
int max_str_lenght = MAX - 1; //We reserve the last slot for \0
int i=0;
if ( fgets( str_line, max_str_lenght, stdin)== NULL)
return -1;
else if( (i = strlen(str_line))== 0 )
return -1;
printf("Array has lenght: %d\n", i-1); // i-1 because it counts also \0 and we don't want this
return i-1;
}
int longest_word ( char str_line[MAX], int str_len, int *n)
{
int i=0;
int temp_len=0; //Stores temporary lenght
int max_len=0; //Stores maximum lenght
for ( i=0; i < str_len; i++)
{ temp_len = 0;
while ( str_line[i] != ' ' && str_line[i] != '\0' && str_line[i] != '\n')
{
if ( isalpha(str_line[i]) && str_line[i] != '\n' )
{
temp_len++;
i++;
}
}
if ( temp_len >= max_len )
max_len = temp_len;
}
for ( i=0; i < str_len; i++)
{
temp_len=0;
while( isalpha(str_line[i]))
{
temp_len++;
i++;
if ( temp_len == max_len)
(*n)++; //We increase by one the counter every time we find a word with max lenght
}
}
return max_len;
}
void get_word ( char str_line[MAX], char word[MAX], int max_lenght, int str_len, int *actual_index, int *flag)
{
int i, j;
int temp_len=0;
erase_array(word);
for ( i = *actual_index, j = 0; isalpha(str_line[i]); j++, i++)
;
*actual_index = i + 1;
if ( j == max_lenght)
{
temp_len = j;
i -= max_lenght;
strncpy(word, str_line + i, max_lenght);
*flag = 1;
}
else
*flag = 0;
str_line += *actual_index;
}
L'unico intoppo è con le lettere accentate che pare non rientrino nel isalpha... Ma è una cosa di cui sinceramente non mi importa, visto che alla fine si tratta di aggiungere condizioni agli if per fargli digerire accenti e apici...
Il programma non è sicuramente ottimizzato, ho infatti notato che alcuni if possono essere tolti e alcuni controlli sono inutili, ma non è ciò che mi interessa. L'obiettivo di completare il programma e renderlo funzionante è riuscito, quindi fine.
Grazie a tutti per l'aiuto e al prossimo programma :D
vBulletin® v3.6.4, Copyright ©2000-2026, Jelsoft Enterprises Ltd.