在字符串上循环并检查它是否只包含特定字符

loop over a string and check if it only contains specific characters

本文关键字:是否 包含特 字符 检查 字符串 循环      更新时间:2023-10-16

我试图遍历一系列DNA序列,以检查该序列是否是有效的DNA序列,我过去使用python进行编码,但现在我正在尝试学习C++,我找到了这个问题的许多答案,但找不到一个简单的答案。我的问题是,如何在字符串上循环并检查它是否只包含一组有效字母?

这与使用python的函数相同:

#!/usr/bin/env python
def isDNA(seq):
    seq = seq.upper()
    flag = True
    for base in seq:
        if base not in ['A', 'T', 'G', 'C']:
            flag = False
            break
    return flag

这是我第一次尝试C++,虽然我认为它的逻辑是正确的,但它不起作用!

#include<string>
#include<iostream>
using namespace std;
bool isDNA(string seq){
    bool flag = true;
    for (int i =0; i <= seq.length(); i++){
        seq[i] = toupper(seq[i]);
        if (seq[i]!='A' && seq[i]!= 'T' && seq[i] != 'G' && seq[i] !='C'){flag= false;break;}
        }
    return flag;
}

int main(){
    string DNA1 = "ACGT";
    string DNA2 = "acgt";
    string DNA3 = "ATTF";
    string DNA4 = "aafg";
    cout << isDNA(DNA1)<<endl;
    cout << isDNA(DNA2)<<endl;
    cout << isDNA(DNA3)<<endl;
    cout << isDNA(DNA4)<<endl;
    return 0;
}

输出是0,0,0,0,我认为它是1,1,0,0

for (int i =0; i <= seq.length(); i++)

应该是

for (int i =0; i < seq.length(); i++)

您正在读取seq[seq.length()],它是0,因此不是允许的字符之一,因此您的函数将始终返回false。

for (int i =0; i <= seq.length(); i++)

你在读字符串的大小。如果seqlength()为10,则其元素从[0]变为[9]。在循环中,您还访问了不属于字符串的元素[10],并且您的函数将返回false。将<=更改为<

您可以执行以下操作:

bool isDNA(string seq){
        for (int i =0; i < seq.length(); i++){
            char c = toupper(seq[i]);
            if (c !='A' && c != 'T' && c != 'G' && c !='C'){return false;}
            }
        return true;
    }
  1. 正如@interjay所说,您正在尝试访问seq[seq.length()],它超过了string的总大小。因此,条件CCD_。

  2. 不需要使用flag变量。直接从该方法返回也可以。

  3. 由于将toUpper()的结果存储回参数字符串只会更改本地副本,因此使用char可以提高可读性。

如果你想要简单,std::string提供了一些搜索功能。我不知道这是比其他解决方案快还是慢,但它确实有效。

bool isDNA(const std::string &seq) {
    return seq.find_first_not_of("ATGCatgc") == std::string::npos;
}

我将在这里提供Python版本的"翻译"。

#include <set>
#include <string>
//#include whatever toupper is from
bool isDNA(const std::string & candidate)
{
    std::set<char> valid_chars = {'A', 'C', 'G', 'T'}; // "Initialization list", C++11 only I think
    for (auto c : candidate) // C++ "for in", C++11 req'd
    {
        if(0 == valid_chars.count(toupper(c))) // will return 0 or 1
        {
            return false; // c isn't in valid_chars
        }
    }
    return true;
}

虽然没有尽可能优化,但你可能会发现它更容易阅读。

还要求C++11获得特别的"for:"样式循环(对像我这样不会计数的人来说很好;不需要逐个考虑(和auto(如果你不太关心类型(。