从字符串中删除重复字符的函数仅适用于相邻字符
Function to remove repeated characters from a string only partially works with adjacent characters
我知道这是一个经常被问到的问题,如果它很愚蠢,我深表歉意,但我正在尝试从文件中的字符串中删除重复的字符并将新字符串放入另一个文件中。这部分进展顺利。
我遇到的主要问题是我的算法删除字符,它仅适用于相同的连续字符,即使这样也只能部分使用。我正在尝试在 for 循环中用户.erase()
这样做,但正如我所说,它不起作用。我哪里出错了?
string removeRepeats(string strIn,string &strOut){
int i;
int len = strIn.length();
for(i = 0;i < len; i++){
if(strIn[i] == strIn[i+1]){
strIn.erase(i+1,1);
}
len = strIn.length();
}
return strOut = strIn;
}
这些是示例文件中输入字符串中的字符串:
aaaaaabbccccc
nnnnmmmvvv
rocko
refrigerate pool
fungus
这是它们在程序运行后的结果:
aaabccc
nnmmvv
rocko
refrigerate
pol
fungus
你只检查相邻的字符:if(strIn[i] == strIn[i+1]) { ...
您可以更有效地做到这一点,但我想先发表一些评论:
返回或通过引用传递,但不能同时返回两者
- 返回
strOut
并通过引用传递strOut
。您应该选择一个或另一个。在我下面写的代码中,我选择返回strOut
.
最小化变量的范围
- 与 C 不同,在 C++ 中,您可以在
for
循环中初始化变量。您还需要尝试最小化循环变量以外的其他变量的范围。在代码中创建一个变量len
。如果您改用for(size_t i = 0; i < strIn.length(); ++i)
,则无需在if
-语句后更新它。
返回作业简直太奇怪了
-
return strOut = strIn;
很奇怪。您不会经常在C++中看到这种情况(请参阅返回或按引用传递,但不能同时看到两者(。如果你真的想return strOut
,在你改变它之前创建一个strIn
的副本并在副本上做所有的字符串突变会更有意义。
以下是我将对您的代码所做的更改(无论算法的正确性如何(:
std::string removeRepeats(std::string strIn){
std::string strOut = strIn;
for(size_t i = 0;i < strOut.length(); ++i){
if(strOut[i] == strOut[i+1]){
strOut.erase(i+1,1);
}
}
return strOut;
}
你会发现,这要干净得多。
现在解决您的问题。
由于只有 128 个 ASCII 字符,您可以创建一个布尔数组并检查您以前是否见过某个字符。
因为您想保留最后一个重复字符,所以我们需要有点棘手。下面是将保留第一个重复字符的代码。
C++11 已批准
std::string remove_repeats(std::string input_string) {
// You have seen no characters yet
bool seen[128] = { false };
std::string output_string = "";
// for every character in the string
for(auto c: input_string) {
// if we haven't seen the the ASCII yet
if(!seen[128-c]) {
// append it to our output string
output_string+=c;
// mark the letter as seen
seen[128-c] = true;
}
}
return output_string;
}
这是 ideone。
如果不能使用 C++11,可以执行以下操作:
std::string remove_repeats(std::string input_string) {
// You have seen no characters yet
bool seen[128] = { false };
std::string output_string = "";
// for every character in the string
for(size_t i = 0; i < input_string.length(); ++i) {
char c = input_string[i];
// if we haven't seen the the ASCII yet
if(!seen[128-c]) {
// append it to our output string
output_string+=c;
// mark the letter as seen
seen[128-c] = true;
}
}
return output_string;
}
这是非 C++11 版本的 ideone。
然而
你想保留最后一个。这就是它变得有趣的地方。
如果我们反转字符串 (1(,运行我们的算法 (2(,然后重新反转 (3(,我们将得到所需的输出:
(1(《你好世界》->《DLROW Olleh》
(2("DLROW Olleh"->"DLROW EH">
(3("DLROW EH"->"他世界">
具体操作方法如下:
std::string remove_repeats(std::string input_string) {
// You have seen no characters yet
bool seen[128] = { false };
// Reverse the input string
std::reverse(input_string.begin(), input_string.end());
std::string output_string = "";
// for every character in the string
for(auto c: input_string) {
// if we haven't seen the the ASCII yet
if(!seen[128-c]) {
// append it to our output string
output_string+=c;
// mark the letter as seen
seen[128-c] = true;
}
}
// Reverse the output string
std::reverse(output_string.begin(), output_string.end());
return output_string;
}
请务必#include <algorithm>
std::reverse
。
最终工作理念
所以你需要做的是在寻找重复的字符时,你是否在现有的for循环中嵌套了一个嵌套的for循环,所以:
string removeRepeats(string strIn,string &strOut){
int i;
int k;
int len = strIn.length();
for(i = 0;i < len; i++){
for(k = i+1 ; k < len; k++){
if(strIn[i] == strIn[k]){
strIn.erase(k,1);
k--;
}
}
len = strIn.length();
}
return strOut = strIn;
}
这将修复程序的比较部分。 你的问题在于你的代码只检查每个数字后面紧随其后的数字,而不是所有其他字符
- 为字符串中每 N 个字符插入空格的函数没有按照我认为的方式工作?
- 使用.find函数在c++中查找字符和另一个字符之间的大小
- 将字符随机转换为大写的函数
- 固有构造函数的字符和访问级别
- constexpr 函数获取常量字符*
- 将字符缓冲区强制转换为函数指针
- 函数签名与调用的函数不匹配,常量字符[]和字符*之间的区别?
- 将字符串数组传递给接受常量字符**的函数
- 在函数中返回无符号字符数组,但不返回指针
- 如何返回实际值(在我的例子中是无符号字符数组)而不是来自 C++ 函数的指针?
- 在函数 strcpy() 中访问字符数组时出现分段错误
- 如何循环访问 cpp 中的函数返回的字符指针数组
- 自定义 std::fstream,std::filebuf 的溢出和下溢函数未为每个字符调用
- 如何在字符函数中选择某些字符?
- 使用排序函数 c++ 对字符数组进行排序
- 字符串到字符* 函数
- 空间字符函数
- 在字符函数中传递字符值时出现奇怪的错误
- 正在更新字符* 函数C++
- 反转字符函数,但不会输出