結果を何に使用するかによって少し異なります。文字列の変更、統計情報の出力、単語のコピーなどに使用されますか? 定数文字列をサポートする必要があるかどうかなど、スレッド セーフである必要がありますか? 効率と単純さの中で最も重要なことは何ですか。
1 つのアプローチは、ポインター全体に依存することです。
- 最初の単語へのポインタ
ptr1
.
- 次の単語へのポインタ
ptr2
.
ptr1
単語と単語をチェックしますptr2
。
ptr2
次の単語に進みます。
- 一致が見つからない場合は、Goto 1.
- 一致が見つからない場合は、
ptr2
次の単語に進みます。
- 後藤2。
単語を比較するための骨組みは、次のようになります。
int compare_word(char *word1, char *word2)
{
int i;
for (i = 0;
word1[i] && word2[i] &&
word1[i] == word2[i] &&
isalpha(word1[i]); ++i)
;
return i && !isalpha(word1[i]) && !isalpha(word2[i]);
}
単語間の距離を計算するときに覚えておくべきことの 1 つは、utf-8 などのマルチバイト文字列形式に注意することです。1文字が数バイトになる場合があります。
a æøå a
^---^ 8 bytes, 5 characters.
を使用mbstowcs
してマルチバイト シーケンスの長さを取得できますが、ロケールにも注意する必要があります。典型的なシナリオ:
char *test = "æøå";
printf("%s: %u\n", test, mbstowcs(NULL, test, 0));
printf("%s: %u\n", test, strlen(test));
setlocale(LC_ALL, "");
puts("-----------------------------------------------");
printf("%s: %u\n", test, mbstowcs(NULL, test, 0));
printf("%s: %u\n", test, strlen(test));
結果:
æøå: 4294967295
æøå: 6
-----------------------------------------------
æøå: 3
æøå: 6
とにかく。概念のサンプルとして、ここにいくつかのコード行があります。これはバイトセーフではないことに注意してください – (ASCII のみが適切な結果をもたらします)。点線の末尾の数字は、「距離: 単語 1 の先頭から単語 2 の先頭まで」、「単語 1 の末尾から単語 2 の先頭までの距離」、および「単語幅」です。出力例:
$ ./wordword
Enter one sentence:
Lizzie Borden took an axe And gave her mother forty whacks When she saw what she had done She gave her father forty-one.
Lizzie Borden took an axe And gave her mother forty whacks When she saw what she had done She gave her father forty-one.
^---------------------------------------------------------------^ (64, 60, 4)
MATCH: 'gave' 60 bytes of separation. (Press enter for next.)
Lizzie Borden took an axe And ____ her mother forty whacks When she saw what she had done She ____ her father forty-one.
^---------------------------------------------------------------^ (64, 61, 3)
MATCH: 'her' 61 bytes of separation. (Press enter for next.)
Lizzie Borden took an axe And ____ ___ mother forty whacks When she saw what she had done She ____ ___ father forty-one.
^---------------------------------------------------------------^ (64, 59, 5)
MATCH: 'forty' 59 bytes of separation. (Press enter for next.)
Lizzie Borden took an axe And ____ ___ mother _____ whacks When she saw what she had done She ____ ___ father _____-one.
^------------^ (13, 10, 3)
MATCH: 'she' 10 bytes of separation. (Press enter for next.)
サンプルコード。(わかりました、ここでは少しやり過ぎました。30 行から始めて、少し大きくなりました。しかし、それでもかなりの数の欠点があり、ポインターなどを使用した例としてのみ意図されています。):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define FMT_BBLACK "\033[1;30m" /* Bold color black */
#define FMT_BRED "\033[1;31m" /* Bold color red */
#define FMT_BGREEN "\033[1;32m" /* Bold color green */
#define FMT_BYELLOW "\033[1;33m" /* Bold color yellow */
#define FMT_BBLUE "\033[1;34m" /* Bold color blue */
#define FMT_BMAGENTA "\033[1;35m" /* Bold color magenta */
#define FMT_BCYAN "\033[1;36m" /* Bold color cyan */
#define FMT_BWHITE "\033[1;37m" /* Bold color white */
#define FMT_NONE "\033[0m" /* Reset */
#define FMT_MATCH FMT_BRED
#define DEL_NONE 0x00 /* Keep words. (Causes re-match) */
#define DEL_WORD1 0x01 /* Remove first word-match */
#define DEL_WORD2 0x02 /* Remove second word-match */
#define DEL_BOTH (DEL_WORD1 | DEL_WORD2)
/* Print graph */
int debug = 1;
/* ********************************************************************** *
* Helper functions
* ********************************************************************** */
/* Return pointer to next alpha,
* or null on end of string) */
char *skip_noword(char *p)
{
while (*p && !isalpha(*p))
++p;
return p;
}
/* Return pointer to byte after last alpha,
* or null on end of C-string */
char *eof_word(char *p)
{
while (*p && isalpha(*p))
++p;
return p;
}
/* Return pointer to first letter of next word,
* or null on end of C-string. */
char *next_word(char *p)
{
p = eof_word(p);
return skip_noword(p);
}
/* Compare whole word starting at p1 with word starting at p2.
* Return 1 on match, else 0.
* */
int compare_word(char *p1, char *p2)
{
int i;
for (i = 0;
p1[i] && p2[i] &&
isalpha(p1[i]) &&
p1[i] == p2[i]; ++i)
;
return i && !isalpha(p1[i]) && !isalpha(p2[i]);
}
/* ********************************************************************** *
* Search routine
* ********************************************************************** */
/* Find next word with a matching entry.
* Return pointer to first word.
* Set match to matching entry.
* */
char *word_word(char *buf, char **match)
{
char *p;
*match = NULL;
buf = skip_noword(buf);
/* Outer loop.
* Advance one and one word. */
while (*buf) {
/* Inner loop.
* Compare current buf word with rest of words after it. */
p = next_word(buf);
while (*p) {
if (compare_word(buf, p)) {
*match = p;
return buf;
}
p = next_word(p);
}
buf = next_word(buf);
}
return (char*)NULL;
}
/* ********************************************************************** *
* Clear, Copy, Print etc.
* ********************************************************************** */
/* Bytes between end of one word to beginning of next.
* */
size_t words_dist(char *w1, char *w2)
{
return w2 - eof_word(w1);
}
/* Replace all alpha characters with given char.
* */
void clear_word(char *p, char r)
{
while (*p && isalpha(*p))
*p++ = r;
}
/* Return a copy of word pointed to by p.
* */
void *word_cpy(char *p)
{
void *buf;
char *start = p;
size_t n;
n = eof_word(p) - start + 1;
if (!(buf = malloc(n)))
return (void*)NULL;
memcpy(buf, start, n);
((char*)buf)[n - 1] = 0x00;
return buf;
}
/* Print graph showing position of p2 and p3 in p1.
* */
void explain(char *p1, char *p2, char *p3)
{
size_t n1 = p3 - p2;
size_t n2 = words_dist(p2, p3);
puts(p1);
while (p1++ != p2)
putchar(' ');
putchar('^');
while (++p2 != p3)
putchar('-');
printf("^ (%d, %d, %d)\n", n1, n2, n1 - n2);
}
/* Print C-string using color.
*
* */
void print_word(FILE *out, char *word)
{
fprintf(out, "%s%s%s", FMT_MATCH, word, FMT_NONE);
}
/* Print single word pointed to by p in (longer) C-string.
* Use dynamic buffer.
* */
void print_word_safe(FILE *out, char *p)
{
char *word;
if (!(word = word_cpy(p)))
return;
print_word(out, word);
free(word);
}
/* Print single word pointed to by p in (longer) C-string.
* Modify and reset source.
* */
void print_word_mod(FILE *out, char *p)
{
char *start = p;
char csave;
p = eof_word(p);
csave = *p;
*p = 0x00;
print_word(out, start);
*p = csave;
}
/* ********************************************************************** *
* Main
* ********************************************************************** */
int main(int argc, char *argv[])
{
char buf_scan[4096]; /* Buffer holding typed input. */
char *buf_start; /* Start of buffer. */
char *buf_pos; /* Current position in buffer. */
char *match; /* Position for matched word. */
int delete; /* Delete flag mask. */
debug = 1; /* 1=Print explanation. */
delete = DEL_BOTH; /* DEL_[NONE, WORD1, WORD2, BOTH] */
if (argc > 1) {
/* Use first argument instead of user input. */
buf_start = argv[1];
} else {
/* Get user input. */
buf_start = buf_scan;
fputs("Enter one sentence:\n", stderr);
if (!fgets(buf_scan, sizeof(buf_scan) - 1, stdin))
buf_scan[0] = 0x00;
buf_scan[strlen(buf_scan) - 1] = 0x00;
putc('\n', stderr);
}
buf_pos = buf_start;
/* Get next matching pair. */
while ((buf_pos = word_word(buf_pos, &match))) {
if (debug)
explain(buf_start, buf_pos, match);
/* Report findings */
fputs("MATCH: ", stderr);
print_word_mod(stderr, buf_pos);
fprintf(stderr,
" %d bytes of separation.",
words_dist(buf_pos, match)
);
/* Clear out matched word pair. */
if (delete & DEL_WORD1) {
clear_word(buf_pos, '_');
}
if (delete & DEL_WORD2) {
clear_word(match, '_');
}
/* Advance head to next word. */
buf_pos = next_word(buf_pos);
fputs(" (Press enter for next.)", stderr);
getchar();
putc('\n', stderr);
}
if (0 && debug)
printf("FINE:\n%s\n\n", buf_start);
return 0;
}