按字典顺序比较两个字符串中的第 k 个单词

to lexicographically compare kth word from two strings

我正在尝试编写一个 C++ 函数来按字典顺序比较两个字符串中的第 k 个单词。这是我的功能:

bool kth_lexo ()
{
    int k = 2 ;
    str1 = "123 300 60009" ;
    str2 = "1500 10002" ;

// to store the kth word of fist string in ptr1
    char *ptr1 = strtok( (char*)str1.c_str() ," "); 
    for(int i = 1; i<k; i++)
    {
        ptr1 = strtok(NULL," ");
    }

// to store the kth word of second string in ptr2
    char *ptr2 = strtok( (char*)str2.c_str() ," "); 
    for(int i = 1; i<k; i++)
    {
        ptr2 = strtok(NULL," ");
    }

    string st1 = ptr1 ;
    string st2 = ptr2 ;
    return st1 > st2 ;


} 

在这个函数中,我的字典顺序比较工作正常,因为这个函数 returns 1 因为 300(str1 的第二个单词)在字典顺序上大于 10002(str2 的第二个单词)

我的问题: 如果我通过用 return ptr1>ptr2 ;

替换上一个函数的最后一行来稍微修改我的函数

现在我的新功能看起来像这样:

bool kth_lexo ()
{
    int k = 2 ;
    str1 = "123 300 60009" ;
    str2 = "1500 10002" ;

// to store the kth word of fist string in ptr1
    char *ptr1 = strtok( (char*)str1.c_str() ," "); 
    for(int i = 1; i<k; i++)
    {
        ptr1 = strtok(NULL," ");
    }

// to store the kth word of second string in ptr2
    char *ptr2 = strtok( (char*)str2.c_str() ," "); 
    for(int i = 1; i<k; i++)
    {
        ptr2 = strtok(NULL," ");
    }

// modified line compared to previous function
    return ptr1 > ptr2 ;


}

对于这个修改后的函数,每次我的输出始终为 0,无论存储在 ptr1 中的 str1 的第 k 个字按字典顺序大于还是小于存储在 ptr2 中的 str2 的第 k 个字。

即使通过此行修改 return 语句也没有带来太大帮助: return (*ptr1)>(*ptr2) ;

那么我修改后的函数中用于比较两个字符串的第 k 个单词的这两个 return 语句行有什么问题:

return ptr1 > ptr2 ;

return (*ptr1) > (*ptr2) ;

如果您停止使用 C 而转而使用 C++,则不会出现此问题。

您在这里混淆了 C++ std::stringchar*const char*。基本上,对于字符串,std::string 优于旧式 C 字符数组或 char*,从现在开始和将来您永远不应该使用 std::string

字符指针是指向内存中存储字符数据的某个区域的地址。使用 * 取消引用指针,将为您提供存储在此地址的元素。所以只有一个元素。不是字符串或其他任何东西。只有一个字符。

比较ptr1 > ptr2 ,不会比较字符串。它将比较一些值,其中字符串存储在内存中。 “ptr1”可以是 0x578962574,“ptr2”可以是 0x95324782,或其他。我们不知道地址。这将由链接器定义。

如果你比较 (*ptr1)>(*ptr2),那么你只比较 2 个单个字符,这也可能给你错误的结果。

另一方面,比较 2 std::strings,将始终按预期工作。

所以,简单的答案:对所有字符串使用 std::string

您正在使用非常类似于 C 的程序。使用现代 C++ 使这变得更简单和更容易阅读,因为我们可以使用非常有表现力的语法:

#include <string_view>
#include <iostream>
#include <cassert>

auto find_kth_char(std::string_view to_search, char c, std::size_t k, std::size_t pos = 0) {
    for (; pos < std::string_view::npos && k > 0; --k) {
        pos = to_search.find(c, pos + 1);
    }
    return pos;
}

auto get_kth_word(std::string_view to_search, std::size_t k) {
    // We count starting on 1
    assert(k > 0);
    auto start = find_kth_char(to_search, ' ', k - 1);
    if (start == std::string_view::npos) {
        return std::string_view{};
    }

    auto end = find_kth_char(to_search, ' ', 1, start);

    return to_search.substr(start, end - start);
}

auto compare_kth(std::string_view lhs, std::string_view rhs, std::size_t k) {
    auto l_word = get_kth_word(lhs, k);
    auto r_word = get_kth_word(rhs, k);

    // returnvalue <=> 0 == lhs <=> rhs
    return l_word.compare(r_word);
}

int main() {
    auto str1 = "123 300 60009";
    auto str2 = "1500 10002";

    for (std::size_t k = 1; k < 4; ++k) {
        std::cout << k << ":\t" << compare_kth(str1, str2, k) << '\n';
    }
}

我正在使用 C++17 的 string_view,因为我们不更改字符串中的任何内容,并且采用子字符串等对它们来说非常便宜。我们使用 find and compare 成员函数来完成实际工作。

我们函数的 return 值是一个整数,它告诉我们左侧是否小于(负结果)、等于 (0) 或大于(正结果)右侧。