如果某个字符是某个字符并且该字符中的前一个字符相同,则跳过该字符

时间:2012-08-31 19:50:07

标签: c++ algorithm language-agnostic cstring

我问了一个类似的问题,但遗漏了一个重要细节。我正在对一组字符(cstring)进行一些文本处理。输入数组被复制到输出数组,除了某些字符被改变(例如a-> b)。这是通过使用switch语句完成的。我想要的是如果在一行中找到两个或多个特定字符,其中只有一个被复制到新数组(所以我不希望连续两个空格)。

这是我到目前为止所做的工作,但没有跳过某些字符中的两个或更多字符,这是有效的:

char cleanName[ent->d_namlen];
    for(int i = 0; i < ent->d_namlen; i++)
    {
        switch(ent->d_name[i])
        {

            case 'a' :
                cleanName[i] = 'b';//replace a's with b's (just an example)
                break;
            case ' ' ://fall through
            case '-' :
            case '–' :
            case '—' :
                cleanName[i] = '_';//replace spaces and dashes with spaces
                break;
            ....//more case statments
           default: 
                cleanName[i] = ent->d_name[i];
  }
}

例如,如果一行中的两个字符被下划线替换,我该怎么做?我是否只会执行switch声明if(ent->d_name[i] != previous || (ent->d_name[i] != '-' && ent->d_name[i] != '_' && ent->d_name[i] != ' ')

这可能更像是一个算法问题,而不是特定于实现的问题。

输入示例:abbc - d-e
输出:bbbc_d_e (为简单起见,假设'a'映射到'b'但实际上不仅仅是这个)

5 个答案:

答案 0 :(得分:2)

嗯,对于这类文本处理算法,我会使用状态机。

答案 1 :(得分:2)

最简单的方法是在现有转换后使用std::unique自定义谓词:

cleanName.erase(std::unique(std::begin(cleanName), std::end(cleanName),
    [](char c, char d) { return c == '_' && d == '_'; }), std::end(cleanName));

对于char数组:

length = std::unique(cleanName, &cleanName[length],
    [](char c, char d) { return c == '_' && d == '_'; }) - cleanName;
cleanName[length] = '\0';

答案 2 :(得分:0)

需要注意的一点是,对于索引的工作方式,您需要意识到cleanName的长度不一定与输入数组的长度相同。因此,您需要使用索引i。

答案 3 :(得分:0)

我的建议是将最后找到的字符保存在临时变量中。这样,如果出现,您可以忽略相同的字符。有两种方法可以做到这一点:
在切换之后添加while语句,其消耗的每个字符等于找到的最后一个字符。如果cstring有很多重复的字符,这很有用:

 char cleanName[ent->d_namlen];
 char parent;
    for(int i = 0; i < ent->d_namlen; i++)
    {
        switch(ent->d_name[i])
        {
            case 'a' :
                cleanName[i] = 'b';//replace a's with b's (just an example)
                parent = ent->d_name[i];
                break;
            case ' ' ://fall through
            case '-' :
            case '–' :
            case '—' :
                cleanName[i] = '_';//replace spaces and dashes with spaces
                parent = ent->d_name[i];
                break;
            ....//more case statments
           default: 
                cleanName[i] = ent->d_name[i];
        }
        while((parent == ent->d_name[i++]) && ent->d_name[i++] != NULL)
            i++;
    }

这里唯一的问题是,如果你有一系列不同的交错空格和破折号,它可能无法识别它并保留各种&#34; _&#34;。一种解决方案是保留父母的集合而不是单个字符。

另一种方法是在每次迭代中将当前字符与下一个字符进行比较。你保持&#34;父母&#34;变量,在每个开关的情况下,你将当前字符与父字符进行比较,如果它们相同,则不要将它添加到cleanName cstring。

答案 4 :(得分:0)

以下是unique_copy算法和transform_iterator from Boost的想法:

#include <boost/iterator/transform_iterator.hpp>
#include <iterator>
#include <iostream>
#include <string>
#include <algorithm>

char transform(char c)
{
    switch(c) {
        case 'a' :
            return 'b';
        case ' ' :
        case '-' :
        case '–' :
        case '—' :
            return '_';
        default:
            return c;
    }
}

int main()
{
    std::string in = "abbc--d-e";
    std::string out;

    std::unique_copy(
        boost::make_transform_iterator(in.begin(), transform),
        boost::make_transform_iterator(in.end(), transform),
        std::back_inserter(out),
        [](char c1, char c2){ return c1 == '_' && c2 == '_'; });

    std::cout << out; // bbbc_d_e
}