如何在JavaScript中替换所有出现的字符串

Click Upvote 4081 javascript string replace

我有这个字符串:

"Test abc test test abc test test test abc test test abc"

str = str.replace('abc', '');

似乎只删除abc上面字符串中的第一次出现.如何更换所有出现的内容?

Sean Bright.. 4137

str = str.replace(/abc/g, '');

回应评论:

var find = 'abc';
var re = new RegExp(find, 'g');

str = str.replace(re, '');

在回应Click Upvote的评论时,您可以进一步简化它:

function replaceAll(str, find, replace) {
    return str.replace(new RegExp(find, 'g'), replace);
}

注意:正则表达式包含特殊(元)字符,因此盲目传递上述函数中的参数find而不预先处理它以逃避这些字符是危险的.这在Mozilla开发者网络正则表达式JavaScript指南中有所介绍,它提供了以下实用程序功能:

function escapeRegExp(str) {
    return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}

因此,为了使上述replaceAll()功能更安全,如果您还包括以下内容,可将其修改为以下内容escapeRegExp:

function replaceAll(str, find, replace) {
    return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}

  • `replaceAll`实现的主要警告是,如果`find`包含元字符,它将无法工作. (41认同)
  • 这是我自己的函数:`function replaceAll(find,replace,str){var re = new RegExp(find,'g'); str = str.replace(re,replace); 返回str; }` (10认同)
  • 正则表达式是实现"开箱即用"的唯一方法,而不实现自己的'replaceAll'方法.我不是仅仅为了使用它们而建议使用它们. (4认同)
  • @Bennett它是[扩展JavaScript本机类型原型的不良做法](/sf/ask/17360801/). (2认同)

Cory Gross.. 2405

为了完整起见,我开始考虑使用哪种方法来完成这项工作.根据本页其他答案的建议,基本上有两种方法可以做到这一点.

注意:通常,建议不要在JavaScript中扩展内置原型.我仅仅为了说明的目的提供String原型的扩展,显示了String内置原型的假设标准方法的不同实现.


基于正则表达式的实现

String.prototype.replaceAll = function(search, replacement) {
    var target = this;
    return target.replace(new RegExp(search, 'g'), replacement);
};

拆分和加入(功能)实施

String.prototype.replaceAll = function(search, replacement) {
    var target = this;
    return target.split(search).join(replacement);
};

在效率方面我不太了解正则表达式如何在幕后工作,我倾向于倾向于分裂并在过去加入实现而不考虑性能.当我确实想知道哪个更有效率,以及在什么边缘时,我用它作为借口来找出答案.

在我的Chrome Windows 8计算机上,基于正则表达式的实现速度最快,分割和连接实现速度降低了53%.这意味着正则表达式的速度是我使用的lorem ipsum输入的两倍.

查看这个基准测试运行这两个实现.


正如@ThomasLeduc和其他人在下面的评论中所指出的,如果search包含在正则表达式中保留为特殊字符的某些字符,则基于正则表达式的实现可能存在问题.该实现假定调用者将事先转义字符串,或者只传递正则表达式(MDN)中没有表中字符的字符串.

MDN还提供了一种逃避字符串的实现.如果这也被标准化RegExp.escape(str),那将是很好的,但唉,它不存在:

function escapeRegExp(str) {
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
}

我们可以escapeRegExp在我们的String.prototype.replaceAll实现中调用,但是,我不确定这会对性能产生多大影响(甚至可能对于不需要转义的字符串,例如所有字母数字字符串).

  • 此解决方案存在问题,如果您的搜索字符串似乎包含正则表达式表达式的特殊字符,则会对其进行解释.我推荐@Sandy Unitedwolf回答. (31认同)
  • 在Android 4.1上,regexp方法的速度提高了15%,但是你没有逃避要搜索的表达式,因此这个基准测试不完整. (8认同)
  • 第一个会这样做:'bla.bla'.replaceAll('.','_'); "_______".第二个将做'bla_bla',这更通常是你想要做的. (2认同)

Matthew Crum.. 1300

注意:不要在实际代码中使用它.

作为简单文字字符串的正则表达式的替代,您可以使用

str = "Test abc test test abc test...".split("abc").join("");

一般模式是

str.split(search).join(replacement)

在某些情况下,这比使用replaceAll和正则表达式更快,但在现代浏览器中似乎不再是这种情况.因此,这应该只是用作快速入侵,以避免需要转义正则表达式,而不是真正的代码.

  • 它让我感到惊讶,因为我希望这种方法能够分配更多的对象,创造更多的垃圾,因此需要更长的时间,但是当我在浏览器中进行实际测试时,这种方法始终比接受的响应快20%左右.当然,结果可能会有所不同. (134认同)
  • 我自己很好奇,并设置了这个:http://jsperf.com/replace-all-vs-split-join.与其他javascript引擎相比,似乎v8在分割/加入数组时速度很快. (39认同)
  • 非常好 - 在传递特殊字符时也可以避免出现错误的RegExps.我在对象属性中添加了"查找并替换它"的通用标志,但是如果我需要替换"."则担心.或"}"并忘记我在3个月后使用RegEx! (7认同)
  • 我没有看到警告不在生产中使用它的原因.它只是因为你想要替换多次出现而不是首先出现正则表达式而不是逃避正则表达式.只需将这个所谓的"hack"包装在一个漂亮的`replaceAll`函数中,它就像其他任何东西一样可读.由于性能不错,没有理由避免这种解决方案. (6认同)
  • 并且作为String.prototype:`String.prototype.replaceAll = function(f,r){return this.split(f).join(r);}`.用法:`"我的字符串".replaceAll('st','');`生成"我的字符串" (5认同)
  • 很棒的答案!出于兴趣,为什么建议不要在实际代码中使用它? (5认同)
  • 在我的ipad2/safari上,分割/连接比替换慢65%,因此您的结果可能会有所不同. (4认同)
  • @MatthewCrumley感谢您的解释.如果它真的是一个黑客,它是我遇到的最干净的之一.当速度不是一个问题时,能够避免在使用正则表达式来完成工作时需要避免文字转义,这并不总是需要 - 很明显,同意但很容易通过简单的注释解释 - 使用可选链接这个答案:-) (4认同)
  • 我是唯一一个认为2或3的因素并不像这样的事情那么大的人,这可能不是你计划的关键部分吗? (3认同)
  • @SteveChambers就黑客而言,这不是最糟糕的(在我看来),但它仍然是一个黑客.在实际代码中,我会使用内置的`replace`方法,因为在大多数情况下它更清晰,更快. (3认同)
  • @fabi当我在你创建的jsperf上测试它时,我得到`replace()`比这种方法快75%以上.我理解"结果可能会有所不同",但变化很大......你觉得呢? (2认同)

Adam A.. 631

使用带有g标志集的正则表达式将替换所有:

someString = 'the cat looks like a cat';
anotherString = someString.replace(/cat/g, 'dog');
// anotherString now contains "the dog looks like a dog"

在这里也看到

  • 有点傻我认为,但JS全局正则表达式是进行多次替换的唯一方法. (13认同)
  • 从技术上讲,你可以循环使用`var sourceText`来计算实例数(`numOfInstances`)使用`substring`或者分割并计算`thatWhichYouWantToReplace`的长度(以及其他策略)然后执行`for(var i = 0; i <numOfInstances; i ++){sourceText = sourceText.replace('thatWhichYouWantToReplace','');`}或更简单地使用while循环(`while sourceText.indexOf(thatWhichYouWantToReplace> -1){sourceText = sourceText.replace(. ..)`)但我不明白为什么你会这样做,当使用`/ g`是如此简单,可能更高效. (4认同)

jesal.. 102

这是一个基于接受的答案的字符串原型函数:

String.prototype.replaceAll = function (find, replace) {
    var str = this;
    return str.replace(new RegExp(find, 'g'), replace);
};

编辑

如果您find将包含特殊字符,那么您需要转义它们:

String.prototype.replaceAll = function (find, replace) {
    var str = this;
    return str.replace(new RegExp(find.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'), replace);
};

小提琴:http://jsfiddle.net/cdbzL/

  • [不要修改你不拥有的对象](http://www.nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/) (8认同)
  • 但是如果`find`包含在正则表达式中具有特殊含义的`.`或`$`等字符呢? (5认同)

Elias Van Oo.. 84

更新:

这是一个更新有点迟,但因为我偶然发现了这个问题,并注意到我之前的答案不是我很满意的.由于问题涉及替换单个单词,所以没有人想到使用单词边界(\b)

'a cat is not a caterpillar'.replace(/\bcat\b/gi,'dog');
//"a dog is not a caterpillar"

这是一个简单的正则表达式,可以避免在大多数情况下替换部分单词.但是,破折号-仍被视为单词边界.因此在这种情况下可以使用条件来避免替换字符串,如cool-cat:

'a cat is not a cool-cat'.replace(/\bcat\b/gi,'dog');//wrong
//"a dog is not a cool-dog" -- nips
'a cat is not a cool-cat'.replace(/(?:\b([^-]))cat(?:\b([^-]))/gi,'$1dog$2');
//"a dog is not a cool-cat"

基本上,这个问题与这里的问题相同: Javascript将"'"替换为"''"

@Mike,检查我给出的答案... regexp不是替换多次出现的替换的唯一方法,远非它.思考灵活,思考分裂!

var newText = "the cat looks like a cat".split('cat').join('dog');

或者,为了防止替换单词部分 - 批准的答案也会这样做!您可以使用正则表达式来解决这个问题,我承认,这些正则表达式稍微复杂一些,并且作为结果,也有点慢:

var regText = "the cat looks like a cat".replace(/(?:(^|[^a-z]))(([^a-z]*)(?=cat)cat)(?![a-z])/gi,"$1dog");

输出与接受的答案相同,但是,在此字符串上使用/ cat/g表达式:

var oops = 'the cat looks like a cat, not a caterpillar or coolcat'.replace(/cat/g,'dog');
//returns "the dog looks like a dog, not a dogerpillar or cooldog" ?? 

哎呀,这可能不是你想要的.那是什么?恕我直言,一个只有条件地取代'猫'的正则表达式.(即不是单词的一部分),如下:

var caterpillar = 'the cat looks like a cat, not a caterpillar or coolcat'.replace(/(?:(^|[^a-z]))(([^a-z]*)(?=cat)cat)(?![a-z])/gi,"$1dog");
//return "the dog looks like a dog, not a caterpillar or coolcat"

我的猜测是,这符合您的需求.当然,这不是全面的,但它应该足以让你开始.我建议在这些页面上阅读更多内容.这对于完善此表达式以满足您的特定需求非常有用.

http://www.javascriptkit.com/jsref/regexp.shtml

http://www.regular-expressions.info


最后补充:

鉴于这个问题仍然有很多观点,我想我可能会添加一个.replace与回调函数一起使用的例子.在这种情况下,它极大地简化表达,并提供了更大的灵活性,如大小写正确的更换或更换两个catcats一气呵成:

'Two cats are not 1 Cat! They\'re just cool-cats, you caterpillar'
   .replace(/(^|.\b)(cat)(s?\b.|$)/gi,function(all,char1,cat,char2)
    {
       //check 1st, capitalize if required
       var replacement = (cat.charAt(0) === 'C' ? 'D' : 'd') + 'og';
       if (char1 === ' ' && char2 === 's')
       {//replace plurals, too
           cat = replacement + 's';
       }
       else
       {//do not replace if dashes are matched
           cat = char1 === '-' || char2 === '-' ? cat : replacement;
       }
       return char1 + cat + char2;//return replacement string
    });
//returns:
//Two dogs are not 1 Dog! They're just cool-cats, you caterpillar


scronide.. 62

匹配全局正则表达式:

anotherString = someString.replace(/cat/g, 'dog');


Adnan Toky.. 52

These are the most common and readable methods.

var str = "Test abc test test abc test test test abc test test abc"

Method-01:

str = str.replace(/abc/g, "replaced text");

Method-02:

str = str.split("abc").join("replaced text");

Method-03:

str = str.replace(new RegExp("abc", "g"), "replaced text");

Method-04:

while(str.includes("abc")){
    str = str.replace("abc", "replaced text");
}

Output:

console.log(str);
// Test replaced text test test replaced text test test test replaced text test test replaced text


小智.. 52

要更换一次,请使用:

var res = str.replace('abc', "");

要多次更换,请使用:

var res = str.replace(/abc/g, "");


SolutionYogi.. 42

str = str.replace(/abc/g, '');

或者从这里尝试replaceAll函数:

有哪些有用的JavaScript方法可以扩展内置对象?

str = str.replaceAll('abc', ''); OR

var search = 'abc';
str = str.replaceAll(search, '');

编辑:关于replaceAll可用性的澄清

'replaceAll'方法被添加到String的原型中.这意味着它可用于所有字符串对象/文字.

例如

var output = "test this".replaceAll('this', 'that');  //output is 'test that'.
output = output.replaceAll('that', 'this'); //output is 'test this'

  • 你可以为那些不使用原型的人重写replaceAll()函数吗? (2认同)

Emilio Griso.. 39

假设您要将所有'abc'替换为'x':

let some_str = 'abc def def lom abc abc def'.split('abc').join('x')
console.log(some_str) //x def def lom x x def

我试图考虑比修改字符串原型更简单的事情.


Donnie DeBoe.. 35

使用正则表达式:

str.replace(/abc/g, '');


Alireza.. 35

使用RegExp的JavaScript可以为你做这项工作,只是简单地做类似下面,不要忘了/g,之后杰出的事物为全球:

var str ="Test abc test test abc test test test abc test test abc";
str = str.replace(/abc/g, '');

如果您考虑重用,请创建一个函数来为您完成,但不推荐它,因为它只是一个行函数,但如果你大量使用它,你可以写这样的东西:

String.prototype.replaceAll = String.prototype.replaceAll || function(string, replaced) {
  return this.replace(new RegExp(string, 'g'), replaced);
};

并简单地在代码中反复使用它,如下所示:

var str ="Test abc test test abc test test test abc test test abc";
str = str.replaceAll('abc', '');

但是正如我前面提到的,它不会在要写入的行或性能方面产生巨大的差异,只有缓存函数可能会对长字符串产生更快的性能,如果你想重用它也是一个很好的DRY代码实践.


Chris Rosete.. 31

替换单引号:

function JavaScriptEncode(text){
    text = text.replace(/'/g,'&apos;')
    // More encode here if required

    return text;
}

  • 如何更改第二行来替换字符串?这不起作用:text = text.replace('hey','hello'); 任何的想法? (2认同)
  • 当然是Stefan,这里是代码...... text = text.replace(/ hey/g,'hello'); (2认同)

Cole Lawrenc.. 25

这是不使用正则表达式最快版本.

修改了jsperf

replaceAll = function(string, omit, place, prevstring) {
  if (prevstring && string === prevstring)
    return string;
  prevstring = string.replace(omit, place);
  return replaceAll(prevstring, omit, place, string)
}

它几乎是分割和连接方法的两倍.

正如在这里的评论中指出的那样,如果您的omit变量包含place,则不会起作用replaceAll("string", "s", "ss"),因为它总是能够替换该单词的另一个出现.

在我的递归替换上还有另一个带有变体的jsperf甚至更快(http://jsperf.com/replace-all-vs-split-join/12)!

  • 2017年7月27日更新:看起来RegExp现在拥有最近发布的Chrome 59中最快的性能.


小智.. 24

//循环直到数字出现为0.或者只是复制/粘贴

    function replaceAll(find, replace, str) 
    {
      while( str.indexOf(find) > -1)
      {
        str = str.replace(find, replace);
      }
      return str;
    }

  • 这种方法很危险,请不要使用它.如果替换字符串包含search关键字,则会发生无限循环.至少,将`.indexOf`的结果存储在变量中,并将此变量用作`.indexOf`的第二个参数(减去关键字的长度,加上替换字符串的长度). (23认同)

csomakk.. 24

str = str.replace(new RegExp("abc", 'g'), "");

对我来说比上面的答案更好.所以new RegExp("abc", 'g')创建一个RegExp匹配'g'文本("abc")的所有出现(标志).第二部分是替换为,在您的情况下空字符串(""). str是字符串,我们必须覆盖它,因为replace(...)只返回结果,但不是覆盖.在某些情况下,您可能想要使用它.


rakslice.. 21

如果您要查找的内容已经在字符串中,并且您没有方便的regex escaper,则可以使用join/split:

    function replaceMulti(haystack, needle, replacement)
    {
        return haystack.split(needle).join(replacement);
    }

    someString = 'the cat looks like a cat';
    console.log(replaceMulti(someString, 'cat', 'dog'));


Tim Rivoli.. 18

function replaceAll(str, find, replace) {
  var i = str.indexOf(find);
  if (i > -1){
    str = str.replace(find, replace); 
    i = i + replace.length;
    var st2 = str.substring(i);
    if(st2.indexOf(find) > -1){
      str = str.substring(0,i) + replaceAll(st2, find, replace);
    }       
  }
  return str;
}


Owen.. 16

我喜欢这种方法(它看起来更干净):

text = text.replace(new RegExp("cat","g"), "dog"); 


pkdkk.. 13

var str = "ff ff f f a de def";
str = str.replace(/f/g,'');
alert(str);

http://jsfiddle.net/ANHR9/


小智.. 13

while (str.indexOf('abc') !== -1)
{
    str = str.replace('abc', '');
}


小智.. 13

如果字符串包含类似的模式abccc,您可以使用:

str.replace(/abc(\s|$)/g, "")


Black.. 12

以前的答案太复杂了.只需使用这样的替换功能:

str.replace(/your_regex_pattern/g, replacement_string);

例:

var str = "Test abc test test abc test test test abc test test abc";

var res = str.replace(/[abc]+/g, "");

console.log(res);


sajadre.. 12

在不使用任何正则表达式的情况下,最简单的方法是在此处拆分并加入类似代码的代码:

var str="Test abc test test abc test test test abc test test abc";
str.split('abc').join('')


SamGoody.. 10

如果您尝试确保即使在替换后您要查找的字符串也不存在,则需要使用循环.

例如:

var str = 'test aabcbc';
str = str.replace(/abc/g, '');

完成后,你仍然会'测试abc'!

解决这个问题的最简单的循环是:

var str = 'test aabcbc';
while (str != str.replace(/abc/g, '')){
   str.replace(/abc/g, '');
}

但是每次循环都会进行两次替换.也许(有被投票的风险)可以合并为一个稍微更有效但可读性更低的形式:

var str = 'test aabcbc';
while (str != (str = str.replace(/abc/g, ''))){}
// alert(str); alerts 'test '!

在查找重复的字符串时,这可能特别有用.
例如,如果我们有'a ,,, b',我们希望删除所有重复的逗号.
[在这种情况下,可以做.replace(/,+/g,','),但在某些时候,正则表达式变得复杂而且足够缓慢而不是循环.


Cheezy Code.. 10

尽管人们已经提到了正则表达式的使用,但是如果你想要替换文本而不管文本的情况如何,那么有更好的方法.像大写或小写.使用以下语法

//Consider below example
originalString.replace(/stringToBeReplaced/gi, '');

//Output will be all the occurrences removed irrespective of casing.

您可以在此处参考详细示例.


tk_.. 8

您可以简单地使用以下方法

/**
 * Replace all the occerencess of $find by $replace in $originalString
 * @param  {originalString} input - Raw string.
 * @param  {find} input - Target key word or regex that need to be replaced.
 * @param  {replace} input - Replacement key word
 * @return {String}       Output string
 */
function replaceAll(originalString, find, replace) {
  return originalString.replace(new RegExp(find, 'g'), replace);
};


小智.. 7

只需添加 /g

document.body.innerHTML = document.body.innerHTML.replace('hello', 'hi');

// Replace 'hello' string with /hello/g regular expression.
document.body.innerHTML = document.body.innerHTML.replace(/hello/g, 'hi');

/g 意味着全球化


Termininja.. 7

我用p来存储前一个递归替换的结果:

function replaceAll(s, m, r, p) {
    return s === p || r.contains(m) ? s : replaceAll(s.replace(m, r), m, r, s);
}

它将替换字符串s中的所有匹配项,直到可能为止:

replaceAll('abbbbb', 'ab', 'a') ? 'abbbb' ? 'abbb' ? 'abb' ? 'ab' ? 'a'

为了避免无限循环,我检查替换r是否包含匹配m:

replaceAll('abbbbb', 'a', 'ab') ? 'abbbbb'


小智.. 7

以下功能适用于我:

String.prototype.replaceAllOccurence = function(str1, str2, ignore)
{
    return this.replace(new RegExp(str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g,"\\$&"),(ignore?"gi":"g")),(typeof(str2)=="string")?str2.replace(/\$/g,"$$$$"):str2);
} ;

现在调用这样的函数:

"you could be a Project Manager someday, if you work like this.".replaceAllOccurence ("you", "I");

只需将此代码复制并粘贴到浏览器控制台中即可.


User.. 6

大多数人可能会这样做来编码URL.要对URL进行编码,您不仅应考虑空格,还应正确转换整个字符串encodeURI.

encodeURI("http://www.google.com/a file with spaces.html")

要得到:

http://www.google.com/a%20file%20with%20spaces.html


Vitim.us.. 5

我的实现,很自我解释

function replaceAll(string, token, newtoken) {
    if(token!=newtoken)
    while(string.indexOf(token) > -1) {
        string = string.replace(token, newtoken);
    }
    return string;
}

  • replaceAll(“ abc”,“ a”,“ ab”)永不终止 (7认同)

小智.. 5

要替换所有字符,请尝试以下代码:

Suppose we have need to send " and \ in my string, then we will convert it " to \" and \ to \\

因此,该方法将解决此问题。

String.prototype.replaceAll = function (find, replace) {
     var str = this;
     return str.replace(new RegExp(find.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'), replace);
 };

var message = $('#message').val();
             message = message.replaceAll('\\', '\\\\'); /*it will replace \ to \\ */
             message = message.replaceAll('"', '\\"');   /*it will replace " to \\"*/

我正在使用Ajax,并且需要以JSON格式发送参数。然后我的方法如下所示:

 function sendMessage(source, messageID, toProfileID, userProfileID) {

     if (validateTextBox()) {
         var message = $('#message').val();
         message = message.replaceAll('\\', '\\\\');
         message = message.replaceAll('"', '\\"');
         $.ajax({
             type: "POST",
             async: "false",
             contentType: "application/json; charset=utf-8",
             url: "services/WebService1.asmx/SendMessage",
             data: '{"source":"' + source + '","messageID":"' + messageID + '","toProfileID":"' + toProfileID + '","userProfileID":"' + userProfileID + '","message":"' + message + '"}',
             dataType: "json",
             success: function (data) {
                 loadMessageAfterSend(toProfileID, userProfileID);
                 $("#<%=PanelMessageDelete.ClientID%>").hide();
                 $("#message").val("");
                 $("#delMessageContainer").show();
                 $("#msgPanel").show();
             },
             error: function (result) {
                 alert("message sending failed");
             }
         });
     }
     else {
         alert("Please type message in message box.");
         $("#message").focus();

     }
 }

 String.prototype.replaceAll = function (find, replace) {
     var str = this;
     return str.replace(new RegExp(find.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'), replace);
 };


Ferie.. 5

在与主要答案相关的性能方面,这些是一些在线测试

尽管以下是一些使用的性能测试console.time()(它们在您自己的控制台中效果最佳,但是这段时间很短,无法在代码段中看到)

console.time('split and join');
"javascript-test-find-and-replace-all".split('-').join(' ');
console.timeEnd('split and join')

console.time('regular expression');
"javascript-test-find-and-replace-all".replace(new RegExp('-', 'g'), ' ');
console.timeEnd('regular expression');

console.time('while');
let str1 = "javascript-test-find-and-replace-all";
while (str1.indexOf('-') !== -1) {
    str1 = str1.replace('-', ' ');
}
console.timeEnd('while');

有趣的是,如果多次运行它们,即使RegExp解决方案平均来看最快,而while循环解决方案最慢,结果却总是不同的。


VhsPiceros.. 5

我使用split and join或此功能

function replaceAll( text, busca, reemplaza ){
  while (text.toString().indexOf(busca) != -1)
      text = text.toString().replace(busca,reemplaza);
  return text;
}


归档时间:

查看次数:

3190678 次

最近记录:

8 月,3 周 前