【问题标题】:Comparing substring of a character array with another character array in C将字符数组的子字符串与C中的另一个字符数组进行比较
【发布时间】:2014-08-01 05:57:46
【问题描述】:

我有两个名为 arraypiarraye 的字符数组,其中包含我从文件中读取的数字。每个都有1,000,000 个字符。我需要从arraye(本例中为7)的第一个字符开始,在arraypi 中搜索。如果7 存在于arraypi 中,那么我必须搜索arraye 的下一个子字符串(在本例中为71)。然后搜索7187182等,直到arraypi中不存在子字符串。然后我必须简单地将最大子字符串的长度放在一个整数变量中并打印出来。

值得一提的是,arraypi 每 50 个字符包含一个换行符,而 arraye 每 80 个字符包含一个换行符,尽管我认为这不会有问题吗?

我尝试过想办法实现这一点,但到目前为止我还没有想到什么。

【问题讨论】:

  • 对于快速(子)字符串匹配应该使用en.wikipedia.org/wiki/…
  • @petrbel 实际上是knuth-morris-pratt 在这种情况下。由于输入字符串只有一个
  • @IvayloStrandjev 好吧,根据“......然后搜索 718、7182 等等......”,我发现更多的子字符串即将匹配,但更多的方法是可能的 - 如果你期望输入匹配最好使用AH并验证。另一方面,如果您期望子字符串的短序列,KMP 会快得多。
  • @petrbel 这些似乎是不同长度的初始输入的前缀。序列的长度在这里并不重要。重要的是您只为单个字符串构建自动机。我并不是说使用 aho-corasick 是错误的。这简直是​​矫枉过正
  • @IvayloStrandjev 是的,如果只匹配前缀,AH 确实是矫枉过正。

标签: c arrays string substring pi


【解决方案1】:

我不确定我是否做对了。我有这样的想法:

  • 假设我们有整个arraypi 在浏览器中
  • 您使用组合键ctrl+f 进行查找
  • 开始逐字输入arraye 的内容,直到看到红色的不匹配
  • 您想要在此之前可以输入的字符数

如果这是正确的,那么像下面这样的算法应该可以解决问题:

#include <stdio.h>
#define iswhitespace(X) ((X) == '\n' || (X) == ' ' || (X) == '\t')

int main( ) {

    char e[1000] = "somet\n\nhing";
    char pi[1000] = "some other t\nhing\t som\neth\n\ning";

    int longestlen = 0;
    int longestx = 0;
    int pix = 0;
    int ex = 0;
    int piwhitespace = 0;       // <-- added
    int ewhitespace = 0;        // <-- these

    while ( pix + ex + piwhitespace < 1000 ) {

        // added the following 4 lines to make it whitespace insensitive
        while ( iswhitespace(e[ex + ewhitespace]) )
            ewhitespace++;
        while ( iswhitespace(pi[pix + ex + piwhitespace]) )
            piwhitespace++;

        if ( e[ex + ewhitespace] != '\0' && pi[pix + ex + piwhitespace] != '\0' && pi[pix + ex + piwhitespace] == e[ex + ewhitespace] ) {
            // the following 4 lines are for obtaining correct longestx value
            if ( ex == 0 ) {
                pix += piwhitespace;
                piwhitespace = 0;
            }
            ex++;
        }
        else {
            if ( ex > longestlen ) {
                longestlen = ex;
                longestx = pix;
            }
            pix += piwhitespace + 1;
            piwhitespace = 0;
            // the two lines above could be replaced with
            // pix++;
            // and it would work just fine, the injection is unnecessary here
            ex = 0;
            ewhitespace = 0;
        }
    }

    printf( "Longest sqn is %d chars long starting at %d", longestlen, longestx + 1 );

    putchar( 10 );
    return 0;
}

发生了什么,循环首先搜索匹配的起点。在找到匹配之前,它会增加正在检查的数组的索引。当它找到一个起点时,它开始增加包含搜索词的数组的索引,同时保持另一个索引不变。

直到下一次不匹配,即进行记录检查时,搜索词索引被重置并且考生索引再次开始增加。

我希望这有助于,以某种方式,希望不仅仅是解决这个单一的斗争。

编辑:

更改了代码以忽略空格字符。

【讨论】:

  • 基本上我必须在arraypi中找到718281。使用你的类比,我会 CTRL-F arraypi 并从 arraye 的开头开始输入数字,在这种情况下是 718
  • 所以,是的,我认为这意味着我做对了,如果我没记错的话,上面的 C 源代码应该可以解决问题。
  • 我在 DevCPP 中对其进行了测试,但是它打印了 753432,这不是它应该打印的。我目前正在尝试找出原因。
  • 我没有考虑换行,抱歉,这可能会导致问题。让我解决这个问题...
  • 啊那些该死的换行符。昨天我花了一整夜试图从我的阵列中完全删除它们,但没有成功。
【解决方案2】:

好的,因为您显然不是真的想要这个数组,而是两个包含文本的文件,这里有一个合适的解决方案来实现这一点:

#include <stdio.h>
#define iswhitespace(X) ((X) == '\n' || (X) == ' ' || (X) == '\t')

int main( ) {

    FILE * e;
    FILE * pi;

    if ( ( e = fopen( "e", "r" ) ) == NULL ) {
        printf( "failure at line %d\n", __LINE__ );
        return -1;
    }

    if ( ( pi = fopen( "pi", "r" ) ) == NULL ) {
        printf( "failure at line %d\n", __LINE__ );
        return -1;
    }

    int curre = fgetc( e );
    int currpi = fgetc( pi );
    int currentlength = 0;
    int longestlength = 0;
    int longestindex = 0;
    int whitespaces = 0;
    fpos_t startpoint;

    if ( curre == EOF || currpi == EOF ) {
        printf( "either one of the files are empty\n" );
        return -1;
    }

    while ( 1 ) {

        while ( iswhitespace( currpi ) )
            currpi = fgetc( pi );

        while ( iswhitespace( curre ) )
            curre = fgetc( e );

        if ( curre == currpi && currpi != EOF ) {
            if ( currentlength == 0 && fgetpos( pi, &startpoint ) ) {
                printf( "failure at line %d\n", __LINE__ );
                return -1;
            }
            currentlength++;
            curre = fgetc( e );
        }
        else if ( currentlength != 0 ) {
            if ( currentlength > longestlength ) {
                longestlength = currentlength;
                longestindex = startpoint;
            }
            if ( curre == EOF ) {
                printf( "Complete match!\n" );
                break;
            }
            fsetpos( pi, &startpoint );
            rewind( e );
            curre = fgetc( e );
            currentlength = 0;
        }

        if ( currpi == EOF )
            break;

        currpi = fgetc( pi );
    }

    printf( "Longest sequence is %d characters long starting at %d",
                                                    longestlength, longestindex );

    putchar( 10 );
    return 0;
}

它搜索一个起点,在确定当前匹配的长度后存储要返回的起点。确定当前匹配的长度,忽略途中的空格。必要时更新记录长度,完全倒回检索词文件,部分倒回考生文件到存储的位置。

这是我的 e 文件:

somet

hing

这是我的 pi 文件:

some other  nhing    som
eth

ing

这是我得到的输出:

Complete match!
Longest sequence is 9 characters long starting at 20

顺便说一句,据我所知,freadfwrite 的功能并不符合人类直觉。你可以把它想象成,计算机在发出这些功能时使用了它自己理解的语言。

【讨论】:

  • 我在第 29 行尝试输入 if ( ( e = fopen( "e", "r" ) ) == NULL ) { printf( "failure at line %d\n", __LINE__ ); return -1; } 时遇到故障,我回家后会再试一次。
  • 您应该将 "e" 替换为 "yourfilenamefore""pi" 也是如此。您还应该将文件放在由此 C 代码生成的可执行文件旁边。
  • 谢谢你,但是我必须对我从文件中获得的字符填充的数组执行此操作。很抱歉造成混乱。
  • @user3601507 我不明白。在我的另一个答案中,我已经给出了填充数组的解决方案;但后来你开始谈论fgetcs 和freads,这让我觉得你更需要它来存储文件。您到底需要什么,怎么可能有一种解决方案不适合您?
  • 我读取文件 e.txtpi.txt 并将它们的内容放入两个名为 arrayearraypi 的数组中,我使用 calloc 进行内存分配,我必须处理这些二。顺便说一句,您的第一个解决方案确实给了我一个结果,但它是 753432 而不是 718281
【解决方案3】:

您可以使用strstr() 函数。考虑在循环中使用它,返回字符串作为参数之一。

【讨论】:

    猜你喜欢
    • 2016-10-17
    • 1970-01-01
    • 2013-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-03
    • 1970-01-01
    相关资源
    最近更新 更多