[英]Remove most common word from string in C
我需要从 C 中的字符串中删除所有出现的最常见单词。
如果文本中有多个单词重复相同的次数,则该函数应删除最接近字符串开头的最常见单词之一。 省略单词时,不应省略周围的空格和其他字符。 如果接收到的字符串不包含任何单词,则函数不需要做任何事情。
单词被定义为大写和小写字母的数组。 该函数不需要区分大小写字母
我的算法如下:
代码:
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
int number_of_word_occurrence(char *s, char *start, char *end) {
int number = 0;
while (*s != '\0') {
char *p = start;
char *q = s;
while (p != end) {
if (*p != *q)break;
p++;
q++;
}
if (p == end)number++;
s++;
}
return number;
}
int length(char *s) {
char *p = s; int number = 0;
while (*p != '\0') {
p++;
number++;
}
return number;
}
char *remove_most_common(char *s) {
int n, max = INT_MIN;
char *p = s;
// Find max occurrence
while (*p != '\0') {
char *start = p;
int word_found = 0;
while (toupper(*p) >= 'A' && toupper(*p) <= 'Z' && *p != '\0') {
word_found = 1;
p++;
}
if (word_found) {
n = number_of_word_occurrence(s, start, p);
if (n > max)max = n;
}
p++;
}
p = s;
int len = length(s);
char *end = s + len;
int i;
// Removing most common word
while (p != end) {
char *start = p, *pp = p;
int word_found = 0;
while (toupper(*pp) >= 'A' && toupper(*pp) <= 'Z' && pp != end) {
word_found = 1;
pp++;
}
if (word_found) {
n = number_of_word_occurrence(s, start, pp);
// If word has max, then remove it
if (n == max) {
while (pp != end) {
*start = *pp;
start++;
pp++;
}
end -= max; // resize end of string
len-=max;
}
}
p++;
}
s[len+=2]='\0';
return s;
}
int main() {
char s[1000] = "Koristio sam auto-stop da dodjem do znaka stop ali prije stopa sam otvorio dekstop kompjutera stop";
printf("%s ", remove_most_common(s) );
return 0;
}
示例 1:“Koristio sam auto- stop da dodjem do znaka stop ali prije stopa sam otvorio dekstop kompjutera stop ”
输出:“Koristio sam auto- da dodjem do znaka ali prije stopa sam otvorio dekstop kompjutera”
示例 2:“这是字符串。”
输出:“是字符串。”
示例 3:“1 PsT 1 psT 2 3 Pst pstpst pst ”;
输出:““11 2 3 pstpst”
示例 4:“ oneeebigggwwooorrrddd ”;
输出: ””
你能帮我修复我的代码吗? 删除字符时出现一些错误。 另外,如果所有单词出现都相同,您能帮我删除最接近开头的单词吗?
string.h
、 stdlib.h
库中的函数以及 stdio.h 库中的sprintf
和sscanf
函数。 不允许在函数中或全局创建辅助字符串。所有主要问题都是由于字符串是信息源,同时被积极更改。
一般来说,单词没有被正确标记。
以输入"hello world"
为例,当在寻找要删除的词时对字符串进行标记时, hello
、 ello
、 llo
、 lo
和o
中的每一个都被认为是词。 程序在扫描单词时仅将字符串前移一个字符。
程序应该将字符串推进当前标记的长度。
number_of_word_occurrence
在进行比较时将任何子字符串视为有效单词。
对于输入
Koristio sam auto- stop da dodjem do znaka stop ali prije stop a sam otvorio dek stop kompjutera stop
最大计数被错误地发现为5
,用于stop
。 此问题与上述问题复合,并开始删除报告此发生计数的错误标记化数据。
概括地说,这种方法的一个大问题是,当您从字符串中删除一个单词时,该单词的出现次数将会不同,下次找到它时。 看着
hello hello hello world world
此处单词的最大出现次数为3
,即hello
。 循环删除最大单词会第一次看到hello
,检查它的出现次数,发现它是3
,最大值,并删除它。
hello hello world world
对于第二个hello
,现在检查其出现次数将返回2
,因为字符串已更改。 这不是3
的最大值,因此字符串不变。
此外,字符串在更改时不会以空值结尾 - 仅在之后。 意思是搜索一个词可能会读取陈旧的数据,从而产生不好的结果。
对程序可以使用的功能的严格限制(特别是对动态内存和辅助缓冲区的限制)确实提供了非常详尽的解决方案。
一种解决方案是首先发现字符串中任何单词的最大出现count
,并持有指向该单词在字符串中的第一次出现的指针。 然后,执行count
times 操作删除单词的最后一次出现,这样您就可以始终将第一次出现作为比较点。
通过用字符串中紧随其后的所有内容(包括空终止字节)覆盖一个单词来删除它。
这是一个粗略的示例 - 很大程度上未经测试,但为所示示例提供了正确的结果。 使用-DDEBUG
编译以查看更多信息。
#include <ctype.h>
#include <stdio.h>
typedef struct word {
const char *base;
size_t length;
} word;
#define length(s) (span((s), NULL))
size_t span(const char *base, int (*test)(int))
{
const char *end = base;
while (test ? test((unsigned char) *end) : *end)
end++;
return (size_t) (end - base);
}
int eql(word a, word b)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: A{%zu}<<%.*s>> <=> B{%zu}<<%.*s>>\n",
a.length, (int) a.length, a.base,
b.length, (int) b.length, b.base);
#endif
if (!a.length || !b.length || a.length != b.length)
return 0;
if (a.base == b.base)
return 1;
for (size_t i = 0; i < a.length; i++)
if (tolower((unsigned char) a.base[i]) != tolower((unsigned char) b.base[i]))
return 0;
return 1;
}
word get_word(const char *s, const char **end)
{
word w = { 0 };
while (*s && !isalpha((unsigned char) *s))
s++;
w.base = s;
w.length = span(s, isalpha);
*end = (s + w.length);
return w;
}
word find_last(const char *s, word mark, unsigned *count)
{
word last = { 0 };
unsigned c = 0;
for (const char *end; *s; s = end) {
word current = get_word(s, &end);
if (eql(mark, current)) {
last = current;
c++;
}
}
if (count)
*count = c;
return last;
}
word find_most_common(const char *s, unsigned *count)
{
word most_common = { 0 };
*count = 0;
for (const char *end; *s; s = end) {
word current = get_word(s, &end);
if (eql(most_common, current))
continue;
unsigned c;
(void) find_last(s, current, &c);
if (c > *count) {
most_common = current;
*count = c;
}
}
return most_common;
}
void copy(char *dest, char *source, size_t length)
{
for (size_t i = 0; i < length; i++)
dest[i] = source[i];
}
void remove_most_common(char *s)
{
unsigned count = 0;
word common = find_most_common(s, &count);
#ifdef DEBUG
if (count)
fprintf(stderr, "DEBUG: MOST COMMON WORD: [[%.*s]]x%u\n",
(int) common.length, common.base, count);
#endif
size_t len = length(s);
while (count--) {
word last = find_last(s, common, NULL);
copy(
(char *) last.base,
(char *) last.base + last.length,
len - (size_t) (last.base - s) + 1);
len -= last.length;
}
}
int main(void)
{
char buffer[4096];
if (!fgets(buffer, sizeof buffer, stdin))
return 1;
size_t len = length(buffer);
if (len && buffer[len - 1] == '\n')
buffer[len - 1] = 0;
printf("<<%s>>\n", buffer);
remove_most_common(buffer);
printf("<<%s>>\n", buffer);
}
我决定编写一个新函数,从字符串中删除所有出现的单词,这完全符合您的要求。 您只需要提供出处和需要删除的单词即可。
代码:
#include <stdio.h>
#include <ctype.h> // toupper
#include <string.h> // strlen
#include <stdbool.h> // bool
void removeWord(char* source, char* removeThis)
{
int i, j;
bool wordFound;
int sourceLength, removeLength;
sourceLength = strlen(source);
removeLength = strlen(removeThis);
for(i = 0; i < sourceLength; ++i)
{
wordFound = true;
for(j = 0; j < removeLength; ++j)
{
if(toupper(source[i + j]) != toupper(removeThis[j]))
{
wordFound = false;
break;
}
}
// It is not a word if the previous character or after the last one is alphabetic
if(wordFound && (isalpha(source[i + j]) || (i > 0 && isalpha(source[i - 1]))))
{
wordFound = false;
}
if(wordFound)
{
for(j = i; j <= sourceLength - removeLength; ++j)
{
source[j] = source[j + removeLength];
}
--i;
sourceLength -= removeLength;
}
}
}
int main()
{
char string1[] = "Koristio sam auto-stop da dodjem do znaka stop ali prije stopa sam otvorio dekstop kompjutera stop";
removeWord(string1, "stop");
printf("\n%s", string1);
char string2[] = {"This is string."};
removeWord(string2, "this");
printf("\n%s", string2);
char string3[] = "1PsT1 psT2 3Pst pstpst pst";
removeWord(string3, "pst");
printf("\n%s", string3);
char string4[] = "oneeebigggwwooorrrddd";
removeWord(string4, "oneeebigggwwooorrrddd");
printf("\n%s", string4);
char string5[] = "Tomtom";
removeWord(string5, "tom");
printf("\n%s", string5);
return 0;
}
输出:
Koristio sam auto- da dodjem do znaka ali prije stopa sam otvorio dekstop kompjutera
is string.
11 2 3 pstpst
Tomtom
基于此,您应该能够编写部分以找到最常用的单词,将其存储并将其提供给该函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.