JavaScript正则表达式替换多个字母

时间:2015-10-22 16:38:14

标签: javascript regex

我有以下代码用其补体替换DNA串,其中A =>。 T和C< => G.我用非常基本的正则表达式知识来做这件事。如何使用正则表达式重构以下内容以捕获字母并将其替换为补码。

function DNA(strand) {
    return strand.replace(/A|T|C|G/g, x => {
        return (x=="A") ? "T" : (x=="T") ? "A" (x=="C") ? "G" : "C";
    });
}

4 个答案:

答案 0 :(得分:3)

这是相当不优雅的,IMO,但它是一个(两个?)步骤替换算法,使用javascript正则表达式功能 - 如果你有兴趣,我可以解释它做了什么

function DNA(strand) {
    return strand
        .concat("||TACG")
        .replace(/A(?=.*?(T))|T(?=.*?(A))|C(?=.*?(G))|G(?=.*?(C))|\|\|....$/gi, "$1$2$3$4");
}

请参阅this fiddle(现在已经更新了一些可测试性)来使用它。

这可能看起来像是一个构建正则表达式的简单示例,但它并不是真的(如果你想让它全部都在正则表达式中,那就是)。使用简单的映射表(散列表),拆分字符,重新映射/转换它们以及将它们连接在一起(如@Jared Smith所做的那样)会更有效率,因为正则表达式引擎效率不高。如果这仅仅是为了个人兴趣和学习正则表达式,那么请随时询问任何必要的解释。

编辑jwco:

正如我所说,对于生产级别的解决方案来说,这是相当不优雅的(或者至少是低效率的),但作为艺术作品(?)可能相当优雅。它仅使用JavaScript正则表达式(Regexp)功能,因此没有"正则表达式条件"或者"后瞻",如果JavaScript支持"自由间距",您实际上可以使用正则表达式,如下所示

这是分解正则表达式组件的一种相对常见的方法,用于解释每个部分匹配,查找和捕获的内容:

  A         #  Match an A, literally
  (?=       #  Look ahead, and
    .*?     #    Match any number of any character lazily (as necessary)
    (T)     #    Match and capture a T, literally (into group #1)
  )         #  End look-ahead
|           #-OR-
  T         #  Match a T, literally
  (?=       #  Look ahead, and
    .*?     #    Match any number of any character lazily (as necessary)
    (A)     #    Match and capture an A, literally (into group #2)
  )         #  End look-ahead
|           #-OR-
  C         #  Match a C, literally
  (?=       #  Look ahead, and
    .*?     #    Match any number of any character lazily (as necessary)
    (G)     #    Match and capture a G, literally (into group #3)
  )         #  End look-ahead
|           #-OR-
  G         #  Match a G, literally
  (?=       #  Look ahead, and
    .*?     #    Match any number of any character lazily (as necessary)
    (C)     #    Match and capture a C, literally (into group #4)
  )         #  End look-ahead
|           #-OR-
 \|\|....$  #  match two literal pipes (|), followed by four of any character and the end of the string

此表达式匹配的任何内容(应该是整个字符串的每个部分)都将替换为替换表达式$1$2$3$4。 "全球"只要有更多要测试的字符串,flag(g中的/gi将使其继续尝试匹配。

表达式由五个可能的选项组成(一个用于每个可能的字母开关,然后一个"清理"匹配)。除了匹配的特定字母之外,前四个选项是相同的。每个匹配并消耗一个特定的所需字母,然后"展望未来"在字符串中找到它的"翻译"或者"补充",捕获它而不消耗任何其他东西,然后作为一个成功的替代完成,从而满足整个表达。

由于只有一个匹配组(1-4)可以匹配任何成功的测试字母,因此$1中只有一个反向引用($1$2$3$4等)可能包含捕获的值。对于第五个选项(\|\|....$),没有捕获,因此没有捕获组包含用于替换匹配的值。

在被送入正则表达式引擎之前,字符串||TACG被附加到源,类似于端粒... ... sorta ... - 这提供了替换源,如果源string不包含适当的"补码"在较早的位置(或根本没有?!)的字母。正则表达式中的最后一个选项通过匹配并将其替换为空来有效地删除了这些无关的信息。

这可以针对任何替换集进行,但随着更多更改的附加效果越来越低。正如一位评论者(我希望是快活的)威胁所表明的那样,这种正则表达式的可维护性也是如此......嗯......这将是一个挑战。享受!

答案 1 :(得分:2)

首先,永远不要嵌套三元运算符。试试这个:

DNAmapping = {
    'G': 'C',
    'C': 'G',
    'A': 'T',
    'T': 'A'
};

function reverseDNA(strand) {
    return strand
        .split('')                       //convert to arrray of chars
        .filter(s => s.match(/A|T|C|G/)  //filter bases
        .map(x => DNAmapping[x])         //sub other char
        .join('');                       //turn back into a string
}

现在使用你的正则表达式只返回DNA碱基对中出现的字符。假设你想要保留那个展位中的其他东西:

var reverseDNA = (strand => strand.replace(/A|T|C|G/g, x => DNAmapping[x]));

现在它更接近你原来的,并且可以读取一行内容。

答案 2 :(得分:0)

似乎Jared Smith的回答并不是你想要的,而是你想要的东西更接近你对replace函数的建议。怎么样:

function DNA(strand) {
    var s = strand.replace(/A|T|/g, function(c) {
        return (c=="A") ? "T" : "A";
    });
    s = s.replace(/G|C|/g, function(c) {
        return (c=="G") ? "C" : "G";
    });
    return s;
}

你的建议似乎唯一的问题是嵌套的三元条件。

修改:这是一个稍微不那么优雅的版本switch,但至少在一个函数调用中保存:

strand.replace(/A|T|G|C/g,function(c){
    switch(c) {
        case "A":
        return "T";
        case "T":
        return "A";
        case "C":
        return "G";
        case "G":
        return "C";
        default:
        return "";
    }
})

答案 3 :(得分:0)

您可能希望将函数用作新值而不是对象。你可以这样做;

function DNA(strand) {
    return strand.replace(/A|T|C|G/g, function(x) {
        return (x=="A") ? "T" : (x=="T") ? "A" : (x=="C") ? "G" : "C";
    });
}