【问题标题】:Function that finds whether 2 string are made from same words判断两个字符串是否由相同单词组成的函数
【发布时间】:2013-12-18 09:06:38
【问题描述】:

我需要在 C 中创建一个函数,它可以确定 2 个字符串是否由相同的单词组成。从当前代码中可以看出,我将每个字符串加载到单独的数组中。我做到了,在数组中有单词,所有单词都是小写字母,每个单词之间只有 1 个空格,并且没有所有非字母字符。我虽然可以对字符串进行排序并对其调用 strcmp ,但不能这样做,因为可能存在诸如 "dog dog dog cat" 和 "dog cat" 之类的字符串,这些字符串来自相同的单词,所以该函数应该返回 1,但如果只是排序并使用 strcmp,它就不会。所以我虽然可以将所有重复的单词合并到1中,然后排序和strcmp,但是还有一个问题,当有“dog”和“god”这样的单词时,它们是2个不同的单词,但是函数排序后仍会将它们视为相同。 “狗狗狗猫”“狗猫” - 相同的词 “嗨,你好!!'”“嗨,,,你好,嗨” - 相同的词 我将非常感谢任何帮助。我真的不知道怎么做,坐了好久还是想不通。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int sameWords( const char * a, const char * b)
{
char * array1=NULL;
char * array2=NULL;
int length1=0, length2=0, i=0, j=0;
while(a[i])
  {
  if(i>=length1)
    {
      length1+=250;
      array1=(char*)malloc(length1*sizeof(char));
    }
  if(isspace(a[i]) && !isspace(a[i-1]))
    {
      array1[i]=a[i];
    }
  if(isalpha(a[i]))
    {
      array1[i]=tolower(a[i]);
    }
  i++;
  }
while(b[j])
  {
  if(j>=length2)
    {
      length2+=250;
      array2=(char*)malloc(length2*sizeof(char));
    }
  if(isspace(b[j]) && !isspace(b[j-1]))
    {
      array2[j]=b[j];
    }
  if(isalpha(b[j]))
    {
      array2[j]=tolower(b[j]);
    }
  j++;
  }
}

int main()
{
sameWords("This' is   string !!! ", "THIS stRing is !!  string ");
return 0;
}

【问题讨论】:

  • 您应该尝试从字符串 1 中获取每个真实单词,一次一个,然后查看字符串 2 中是否包含它。如果字符串 1 中的所有单词都在字符串 2 中,则对字符串 1 中包含的字符串 2 单词执行相同的操作。不排序,只需检查每个有效单词是否包含在另一个字符串中。如果字符串 1 中的所有有效单词都在字符串 2 中,反之亦然,那么您就有了匹配项。
  • "'dog' 和 'god' 是两个不同的词,但是排序后函数还是一样。" 为什么?
  • 好的,谢谢。这也是我在想的,但不知如何实现。如何接一个单词并检查它们是否在另一个字符串中。
  • 为什么不实现您对每个 to 字符串的建议:将一个单词的所有出现合并为一个单词并将它们排序,然后比较两个数组。
  • 因为那是狗和上帝的事。 Dog 和 God 是不同的词,我认为它会对字母进行排序,所以它是“dgo”,并且在两个数组中都是相同的“dgo”,所以它会将它们比较为相同。

标签: c arrays string words


【解决方案1】:

您已经学会了两种解决问题的方法。复杂的是将每个字符串拆分为单词,对它们进行排序,然后清除重复项,这在排序数组中很容易。更简单的方法是将第一个字符串拆分为单词,然后在第二个字符串中搜索每个单词。然后反过来做同样的事情:拆分第二个并检查第一个中的单词。

这两种方法都要求您拆分字符串。这也是您的代码似乎存在问题的地方。 (您已经有了查看单词边界的基本概念,但您似乎不知道如何存储单词。)

基本问题是:你将如何表示单词,即 C 字符串的子字符串?有多种方式。您可以将指向字符串的指针与字符串长度一起使用,也可以将它们复制到另一个缓冲区中。

这是一个将字符串a拆分成单词然后检查每个单词是否可以在b中找到的sloution:

/*
 *      Return 1 if all words in a can be found in b, 
 *      return 0 otherwise.
 */
int split_and_check(const char *a, const char *b)
{
    int begin = -1;    /* marker for beginning of word */
    char word[80];     /* temporary buffer for current word */
    int prev = 0;      /* previously read char to detect word bounaries */
    int len;           /* current length of word */
    int i;

    i = 0;
    while (1) {
        if (isalpha(a[i])) {
            if (!isalpha(prev)) {
                begin = i;
                len = 0;
            }
            if (len < 80) word[len++] = a[i];
        } else {
            if (len > 0) {
                word[len] = '\0';       /* manually null-terminate word */

                if (strstr(b, word) == NULL) {
                    /* fail on string mismatch */
                    return 0;
                }
                len = 0;                /* reset word-length counter */
            }
        }
        if (a[i] == '\0') break;        /* check end here to catch last word */
        prev = a[i++];
    }

    return 1;
}

当前字存储在本地字符缓冲区word 中,长度为len。请注意在搜索b 以查找word 之前,如何手动将零结束标记'\0' 添加到word:库函数strstr 在另一个字符串中查找字符串。两个字符串都必须以零结尾。

这只是解决方案的一半。您必须反过来检查字符串:

int same_words(const char *a, const char *b)
{    
    if (split_and_check(a, b) == 0) return 0;
    if (split_and_check(b, a) == 0) return 0;

    return 1;
}

这还不是您问题的确切解决方案,因为字符串匹配是区分大小写的。我跳过了这部分,因为这样更容易:strstr 区分大小写,我不知道任何忽略大小写的变体。

【讨论】:

  • 在解决大小写问题之前,可以将两个数组都转为小写。
  • 非常感谢。我会检查你的代码,我想我可以从中学习如何去做。
【解决方案2】:

我要解决这个问题的方法是创建一个像树一样的数据结构,您可以在其中插入单词。如果单词已经存在,则 insert 函数将不执行任何操作,否则会将其转换为小写并将其插入树中。然后您可以简单地将两个字符串都转换为这些类型的树并比较这些树。

另一种方法是使用 bash。虽然这可能不允许您分配,但如果您了解它的工作原理和原因,您应该能够编写一些模仿它的代码:

# string1 and string2 are simply strings with spaces separating words
s1="dog dog dog cat"
s2="cat dog"

# Convert to arrays
a1=( $(printf "%s\n" ${s1}  | sort | uniq ) )
a2=( $(printf "%s\n" ${s2}  | sort | uniq ) )

# Compare the result
if [ "${a1[*]}" == "${a2[*]}" ] ; then
  echo "Same"
fi

【讨论】:

  • 这个问号不是用C吗?为什么选择 shell 脚本?
  • 我虽然会从 string1 中取出单独的单词并搜索它们是否在字符串 2 中,一个接一个。然后从 2 中取出单词并在 1 中搜索它们。但我不知道如何将单词与字符串分开。这是主要问题。
  • man strtok :) 或谷歌“strtok”。 magic 术语是 tokenize
  • 或者您可以使用 scanf 进行格式化输入。你甚至可以在字符串上使用它。 fscanf 从文件(或 STDIN)中读取,sscanf 从字符串中读取。
  • @hacks 正如我在回答中所说,这可能不适用于 OP 的作业,但这个脚本可以工作。由于是家庭作业,我认为这是一个很好的例子,它并没有为他做所有的工作,而是展示了一个有效的例子,但仍有一些工作要做。
【解决方案3】:

我不假装被授予答案,但我也会看看正则表达式来解决这种事情。

Does C or C++ have a standard regex library?

解决它需要几分钟,你用正则表达式分割字符串,小写,然后迭代来处理常见的单词。

【讨论】:

  • 谢谢,但我可能无法使用 reg.ex。因为这就像学校的家庭作业,我们还没有学习正则表达式,所以我不能使用它们。
  • 可以添加作业的约束吗?你可以使用strtokstrstr 等来自&lt;string.h&gt; 的函数吗?
  • 我可能可以。我不能只使用 STL 和 std::string。
【解决方案4】:

您的函数 sameWords 没有返回任何内容,其返回类型为 int

【讨论】:

  • 应该是250,因为在分配之前有{length1+=250;}
  • 我知道我现在什么都没有返回,但是如果这些字符串来自相同的单词,它应该返回 1,否则返回 0。现在我只需要找出如何找出是否有相同的单词。
  • 好的,很抱歉,但我是编程新手。但现在退货不是问题。
  • 我正在调试你的代码。给我一些时间。它现在可以工作,但还有一些其他问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多