替换文本但保持大小写

Replace text but keep case

提问人:ignacio.munizaga 提问时间:6/24/2013 最后编辑:ignacio.munizaga 更新时间:3/23/2023 访问量:14909

问:

我有一组字符串需要替换,但我需要保留字母的大小写。

输入字和输出字的长度相同。

例如,如果我需要将“abcd”替换为“qwer”,则应发生以下情况:

"AbcD" translates to "QweR"
"abCd" translates to "qwEr"

等等。

现在我正在使用 JavaScript 的 ,但是大写字母在翻译时丢失了。replace

r = new RegExp( "(" + 'asdf' + ")" , 'gi' );
"oooAsdFoooo".replace(r, "qwer");

任何帮助将不胜感激。

JavaScript的

评论

0赞 pvnarula 6/24/2013
目标字符串和替换是已知的,还是动态的?
0赞 ignacio.munizaga 6/24/2013
对不起,我不明白你的问题。但情况是这样的:我正在转录用户输入的文本。我有一个规则列表,比如“ca”转录为“kb”,但我需要保留大写字母,所以“cA”转录为“kB”。
1赞 bert 6/24/2013
我将分两步完成,首先是“oooAsdFoooo”.search(r),它返回索引,然后处理大小写。但是,如果有一种方法只有正则表达式,我会很兴奋
0赞 TommyBs 6/24/2013
你有特定的字母到字母映射列表吗?例如 a==q, A== Q .因此,如果 a 是输入,则始终为 q(大写或小写)
1赞 Syknapse 7/11/2019
我找到了一个更简单、更优雅的解决方案,可以解决这里似乎相同的问题:stackoverflow.com/questions/28841045/......

答:

2赞 Tomalak 6/24/2013 #1
String.prototype.translateCaseSensitive = function (fromAlphabet, toAlphabet) {
    var fromAlphabet = fromAlphabet.toLowerCase(),
        toAlphabet = toAlphabet.toLowerCase(),
        re = new RegExp("[" + fromAlphabet + "]", "gi");

    return this.replace(re, function (char) {
        var charLower = char.toLowerCase(),
            idx = fromAlphabet.indexOf(charLower);

        if (idx > -1) {
            if (char === charLower) {
                return toAlphabet[idx];
            } else {
                return toAlphabet[idx].toUpperCase();
            }
        } else {
            return char;
        }
    });
};

"AbcD".translateCaseSensitive("abcdefg", "qwertyu")

将返回:

"QweR"

评论

1赞 jcsanyi 6/24/2013
不过,这替换了单个字符 - 最初的问题是谈论替换子字符串。在您的示例中,输入字符串不包含“abcdefg”,因此不应替换任何内容。
0赞 Tomalak 6/24/2013
@jcsanyi嗯。我不这么理解。但你很可能是对的。
12赞 Ry- 6/24/2013 #2

下面是一个帮助程序:

function matchCase(text, pattern) {
    var result = '';

    for(var i = 0; i < text.length; i++) {
        var c = text.charAt(i);
        var p = pattern.charCodeAt(i);

        if(p >= 65 && p < 65 + 26) {
            result += c.toUpperCase();
        } else {
            result += c.toLowerCase();
        }
    }

    return result;
}

然后你可以:

"oooAsdFoooo".replace(r, function(match) {
    return matchCase("qwer", match);
});

评论

1赞 Tomalak 6/24/2013
这很好,但仅适用于 ASCII。:)
3赞 Ry- 6/24/2013
@Tomalak:如有必要,请更改为 ,更改为 ,并定义 。p >= 65 && p < 65 + 26UPPERCASE.test(p)charCodeAtcharAtvar UPPERCASE = /[whateverletters]/;
0赞 Ry- 6/24/2013
或者也许.toLocale{Upper,Lower}Case
1赞 TommyBs 6/24/2013 #3

您可以创建自己的替换函数,例如

 if(!String.prototype.myreplace){
String.prototype.myreplace = (function(obj){
    return this.replace(/[a-z]{1,1}/gi,function(a,b){
       var r = obj[a.toLowerCase()] || a;
        return a.charCodeAt(0) > 96? r.toLowerCase() : r.toUpperCase();
    });
});
}

这将接受映射不同字母的对象。它可以这样称呼

  var obj = {a:'q',b:'t',c:'w'};

  var s = 'AbCdea';
  var n = s.myreplace(obj);
  console.log(n);

这意味着如果需要,您可以使用不同的映射传递不同的对象。这是一个显示示例的简单小提琴(请注意,对象全部是小写的,但函数本身也查看字符串的大小写)

评论

0赞 Edie Lemoine 8/12/2021
不建议修改原型以提高可维护性。改为创建导出的函数,并要求或导入它。更多详情:flaviocopes.com/javascript-why-not-modify-object-prototype
1赞 Barry G 2/20/2016 #4

扩展 Ryan O'Hara 的答案,以下解决方案避免使用 charCodes 以及使用它们时可能遇到的问题。它还确保在琴弦长度不同时完成更换。

function enforceLength(text, pattern, result) {
  if (text.length > result.length) {  
    result = result.concat(text.substring(result.length, text.length));
  }

  if (pattern.length > text.length) {
    result = result.substring(0, text.length);
  }

  return result;
}

function matchCase(text, pattern){
  var result = '';

  for (var i =0; i < pattern.length; i++){
    var c = text.charAt(i);
    var p = pattern.charAt(i);

    if(p === p.toUpperCase()) {
       result += c.toUpperCase();
    } else {
       result += c.toLowerCase();
    }
  }  
  return enforceLength(text, pattern, result);
}
1赞 Karan Jariwala 4/15/2017 #5

这应该在保留外壳的同时进行替换。如果有人在此解决方案中发现任何缺陷,请告诉我。我希望这会有所帮助。谢谢!

function myReplace(str, before, after) {

      var match=function(before,after){
        after=after.split('');
        for(var i=0;i<before.length;i++)
          {

            if(before.charAt(i)==before[i].toUpperCase())
              {
                after[i]=after[i].toUpperCase();
              }
            else  if(before.charAt(i)==before[i].toLowerCase())
              {
                after[i]=after[i].toLowerCase();
              }
            return after.join('');
          }

      };
           console.log(before,match(before,after));
          str =str.replace(before,match(before,after)); 


      return str;
    }

    myReplace("A quick brown fox jumped over the lazy dog", "jumped", "leaped");
2赞 Stephen Quan 7/1/2019 #6

下面是一个函数:replaceCase

  1. 我们将输入模式转换为正则表达式
  2. 我们有一个嵌套的替换函数,它遍历每个字符
  3. 我们使用正则表达式来识别大写字母,否则我们假设所有内容都是小写的/[A-Z]/

function replaceCase(str, pattern, newStr) {
  const rx = new RegExp(pattern, "ig")
  const replacer = (c, i) => c.match(/[A-Z]/) ? newStr[i].toUpperCase() : newStr[i]
  return str.replace(rx, (oldStr) => oldStr.replace(/./g, replacer) )
}

let out = replaceCase("This is my test string: AbcD", "abcd", "qwer")
console.log(out) // This is my test string: QweR
out = replaceCase("This is my test string: abCd", "abcd", "qwer")
console.log(out) // This is my test string: qwEr

评论

0赞 Alexander Dixon 5/19/2021
你能用标准的jQuery或普通的JavaScript编写这个函数吗?EMCA 2015 在我们支持的所有浏览器中都不符合要求。
1赞 Eray Chumak 9/22/2020 #7

我有一个句子,我必须用另一个单词替换每个单词,并且该单词可能比它替换的单词更长/更短,因此它类似于问题,但它们不是固定长度,而是动态的。

我的解决方案

为简单起见,我只关注一个词。

const oldWord = "tEsT";
const newWord = "testing";

拆分这两个单词,以便我可以遍历每个单独的字母。

const oldWordLetters = oldWord.split("");
const newWordLetters = newWord.split("");

现在,我将遍历这些字母并使用其索引将相应的字母放在相同的位置。然后我会检查旧字母是否是大写的,如果是,那么在同一位置的新字母也大写。newWordoldWord

for (const [i, letter] of newWordLetters.entries()) {
  const oldLetter = oldWordLetters[i];

  // stop iterating if oldWord is shorter (not enough letters to copy case).
  if (!oldLetter) {
    break;
  }

  const isCapital = oldLetter === oldLetter.toUpperCase();

  // make the new letter in the same position as the old letter capital
  if (isCapital) {
    newWordLetters[i] = letter.toUpperCase();
  }
}

最后的世界将在再次加入字母之后。tEsTing

const finalWord = newWordLetters.join("");

console.log(finalWord); // "tEsTing"

完整代码

const oldWord = "tEsT";
const newWord = "testing";

const oldWordLetters = oldWord.split("");
const newWordLetters = newWord.split("");

for (const [i, letter] of newWordLetters.entries()) {
  const oldLetter = oldWordLetters[i];

  // stop iterating if oldWord is shorter (not enough letters to copy case).
  if (!oldLetter) {
    break;
  }

  const isCapital = oldLetter === oldLetter.toUpperCase();

  // make the new letter in the same position as the old letter capital
  if (isCapital) {
    newWordLetters[i] = letter.toUpperCase();
  }
}

const finalWord = newWordLetters.join("");

console.log(finalWord);

0赞 Pedro 2/11/2021 #8

我认为这可能有效

function formatItem(text, searchText){
    const search = new RegExp(escapeRegExp(searchText), 'iu')
    return text?.toString().replace(search, (m) => `<b>${m}</b>`)
}

function escapeRegExp(text) {
  return text?.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') ?? '';
}
12赞 silvio 11/26/2021 #9

我将把它留在这里供参考。

场景:项目列表上的搜索框不区分大小写,字符串上的部分匹配应突出显示,但保留原始大小写。

highlight() {
  const re = new RegExp(this.searchValue, 'gi'); // global, insensitive
  const newText = name.replace(re, `<b>$&</b>`);
  return newText;
}

$& 是带大小写的匹配文本

0赞 kloddant 5/14/2022 #10

谢谢你问这个问题。当我想搜索文本并用链接替换某些单词时,我遇到了同样的问题,这是一个稍微具体一点的情况,因为它正在用 html 字符串替换文本字符串。我会把我的解决方案放在这里,以防任何发现这种情况的人正在做类似的事情。

let elmt = document.getElementById('the-element');
let a = document.createElement('a');
a.href = "https://www.example.com";
let re = new RegExp('the string to find', 'gi');
elmt.innerHTML = elmt.innerHTML.replaceAll(re, function (match) {
    a.innerText = match;
    return a.outerHTML;
});

因此,正则表达式确保它搜索不区分大小写的匹配项,并且作为 replaceAll 函数的第二个参数的函数指定它应该将新标签的 innerText 设置为等于旧字符串,然后返回整个标签的 outerHTML。

0赞 Rafael Sanabria 9/30/2022 #11

这是一个函数。如果需要,可以通过 .replaceAllCaseSensitivereplaceAllreplace

const replaceAllCaseSensitive = (
  text, // Original string
  pattern, // RegExp with the pattern you want match. It must include the g (global) and i (case-insensitive) flags.
  replacement // string with the replacement
) => {
  return text.replaceAll(pattern, (match) => {
    return replacement
      .split("")
      .map((char, i) =>
        match[i] === match[i].toUpperCase() ? char.toUpperCase() : char
      )
      .join("");
  });
};

console.log(replaceAllCaseSensitive("AbcD abCd", /abcd/gi, "qwer"));
// outputs "QweR qwEr"

console.log(replaceAllCaseSensitive("AbcD abCd", /abcd/gi, "qwe"));
// outputs "Qwe qwE"

即使短于 ,该函数也有效。replacementmatch

0赞 craig 3/23/2023 #12

我真的很喜欢 Stephen Quan 的答案,但发现它不能处理替换字符串与匹配字符串长度不同的情况。这是我对他的回答的更新

const replaceCase = (str, pattern, newStr) => {
  const rx = new RegExp(pattern, 'ig');
  const replacer = (c, i) => (c.match(/[A-Z]/) ? newStr[i].toUpperCase() : newStr[i] ?? '');
  const [match] = str.match(rx) ?? [];
  return str.replace(rx, (oldStr) => oldStr.replace(/./g, replacer)) + newStr.slice(match?.length ?? 0);
};

在 TypeScript 中,适合那些喜欢的人

const replaceCase = (str: string, pattern: RegExp, newStr: string) => {
  const rx = new RegExp(pattern, 'ig');
  const replacer = (c: string, i: number) =>
    c.match(/[A-Z]/) ? newStr[i].toUpperCase() : newStr[i] ?? '';
  const [match] = str.match(rx) ?? [];
  return (
    str.replace(rx, (oldStr) => oldStr.replace(/./g, replacer)) + newStr.slice(match?.length ?? 0)
  );
};