Tương đương với String.format trong jQuery


Câu trả lời:


193

Các mã nguồn cho ASP.NET AJAX có sẵn để bạn tham khảo, vì vậy bạn có thể chọn qua nó và bao gồm những phần bạn muốn tiếp tục sử dụng vào một tập tin JS riêng biệt. Hoặc, bạn có thể chuyển chúng sang jQuery.

Đây là chức năng định dạng ...

String.format = function() {
  var s = arguments[0];
  for (var i = 0; i < arguments.length - 1; i++) {       
    var reg = new RegExp("\\{" + i + "\\}", "gm");             
    s = s.replace(reg, arguments[i + 1]);
  }

  return s;
}

Và đây là phần kết thúc và bắt đầu với các hàm nguyên mẫu ...

String.prototype.endsWith = function (suffix) {
  return (this.substr(this.length - suffix.length) === suffix);
}

String.prototype.startsWith = function(prefix) {
  return (this.substr(0, prefix.length) === prefix);
}

2
Không có vẻ như có nhiều đến đó. Phiên bản JavaScript không có tất cả các công cụ định dạng số ưa thích, rõ ràng. blog.stevex.net/index.php/opes-formatted-in-csharp
Nosredna

Ồ, tôi thực sự đã nghĩ về điều này nhưng cũng nghĩ rằng điều đó là không thể vì giấy phép, không biết họ đã phát hành nó theo Giấy phép của Microsoft, cảm ơn rất nhiều vì điều này
Waleed Eissa

23
Giấy phép hoặc không có giấy phép .. chỉ có một cách đúng để viết một cái gì đó đơn giản
adamJLev

1
Xây dựng (và sau đó loại bỏ) một đối tượng RegEx cho mỗi và mọi đối số mỗi định dạng được gọi có thể vượt qua trình thu gom rác.
mckoss

14
Cảnh báo: Điều này sẽ định dạng đệ quy: vì vậy nếu bạn có {0}{1}, {0}sẽ được thay thế trước, và sau đó tất cả các lần xuất hiện {1}trong cả văn bản đã được thay thế và định dạng ban đầu sẽ được thay thế.
Zenexer

147

Đây là một biến thể nhanh hơn / đơn giản hơn (và nguyên mẫu) của chức năng mà Josh đã đăng:

String.prototype.format = String.prototype.f = function() {
    var s = this,
        i = arguments.length;

    while (i--) {
        s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i]);
    }
    return s;
};

Sử dụng:

'Added {0} by {1} to your collection'.f(title, artist)
'Your balance is {0} USD'.f(77.7) 

Tôi sử dụng nó nhiều đến mức tôi đặt bí danh cho nó f, nhưng bạn cũng có thể sử dụng dài dòng hơn format. ví dụ'Hello {0}!'.format(name)


1
Với các trình duyệt hiện đại, thậm chí còn có nhiều cách tiếp cận đơn giản hơn: stackoverflow.com/a/41052964/120296
david

3
@david Chuỗi mẫu KHÔNG hoàn toàn giống nhau. Chúng là đường cú pháp để nối chuỗi, rất hay nhưng không giống như định dạng. Họ chạy ngay lập tức, do đó, sự thay thế phải nằm trong phạm vi tại điểm định nghĩa. Bạn không thể lưu trữ chúng trong một tệp văn bản hoặc cơ sở dữ liệu vì điều này. Trong thực tế, cách duy nhất để lưu trữ chúng ở bất cứ đâu là đặt chúng vào một chức năng. Hàm chuỗi được định dạng có các thay thế vị trí không quan tâm đến tên của biến.
krowe2

131

Nhiều hàm trên (trừ Julian Jelfs) có lỗi sau:

js> '{0} {0} {1} {2}'.format(3.14, 'a{2}bc', 'foo');
3.14 3.14 afoobc foo

Hoặc, đối với các biến thể đếm ngược từ cuối danh sách đối số:

js> '{0} {0} {1} {2}'.format(3.14, 'a{0}bc', 'foo');
3.14 3.14 a3.14bc foo

Đây là một chức năng chính xác. Đó là một biến thể nguyên mẫu của mã Julian Jelfs, mà tôi đã làm chặt chẽ hơn một chút:

String.prototype.format = function () {
  var args = arguments;
  return this.replace(/\{(\d+)\}/g, function (m, n) { return args[n]; });
};

Và đây là một phiên bản cao cấp hơn một chút, cho phép bạn thoát khỏi niềng răng bằng cách nhân đôi chúng:

String.prototype.format = function () {
  var args = arguments;
  return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (m, n) {
    if (m == "{{") { return "{"; }
    if (m == "}}") { return "}"; }
    return args[n];
  });
};

Điều này hoạt động chính xác:

js> '{0} {{0}} {{{0}}} {1} {2}'.format(3.14, 'a{2}bc', 'foo');
3.14 {0} {3.14} a{2}bc foo

Đây là một triển khai tốt khác của Blair Mitchelmore, với một loạt các tính năng bổ sung thú vị: https://web.archive.org/web/20120315214858/http://blairmitchelmore.com/javascript/opes.format


Và một cái khác, mà tôi đã không xem xét quá kỹ, nhưng dường như triển khai các định dạng như {0: + $ #, 0,00; - $ #, 0,00; 0}: masterdata.dyndns.org/r/opes_format_for_javascript
gpvos

Ồ, và một trong đó sử dụng định dạng nội suy Python: code.google.com/p/jquery-utils/wiki/
mẹo

Việc triển khai định dạng tôi đã đề cập đến hai nhận xét đã được chuyển sang masterdata.se/r/opes_format_for_javascript
gpvos

Lưu ý: câu trả lời của ianj ở nơi khác trên trang này cho phép bạn sử dụng tên thay vì tham số số. Nếu bạn thay đổi phương thức của anh ấy thành phương thức sử dụng nguyên mẫu, bạn sẽ phải thay đổi tham số thứ hai thành hàm sl.call từ 1 thành 0.
gpvos

48

Tạo một hàm định dạng lấy một tập hợp hoặc một mảng làm đối số

Sử dụng:

format("i can speak {language} since i was {age}",{language:'javascript',age:10});

format("i can speak {0} since i was {1}",'javascript',10});

Mã số:

var format = function (str, col) {
    col = typeof col === 'object' ? col : Array.prototype.slice.call(arguments, 1);

    return str.replace(/\{\{|\}\}|\{(\w+)\}/g, function (m, n) {
        if (m == "{{") { return "{"; }
        if (m == "}}") { return "}"; }
        return col[n];
    });
};

5
Một cái hay, tất cả những gì còn thiếu là: String.prototype.format = function (col) {return format (this, col);}
Erik

10
tôi không muốn mở rộng chuỗi
ianj

3
Có một lỗi đánh máy nhỏ trong cách sử dụng: dòng thứ 2 phải là: format ("tôi có thể nói {0} kể từ khi tôi là {1}", 'javascript', 10);
Guillaume Gendre

Tại sao không thích mở rộng chuỗi bằng cách sử dụng String.prototype?
Kiquenet

36

Có một tùy chọn (phần nào) chính thức: jQuery.validator.format .

Đi kèm với Plugin xác thực jQuery 1.6 (ít nhất).
Khá giống với String.Formattìm thấy trong .NET.

Chỉnh sửa liên kết bị hỏng.



13

Mặc dù không chính xác những gì Q yêu cầu, tôi đã xây dựng một cái tương tự nhưng sử dụng trình giữ chỗ có tên thay vì được đánh số. Cá nhân tôi thích có các đối số được đặt tên và chỉ gửi một đối tượng làm đối số cho nó (dài dòng hơn, nhưng dễ duy trì hơn).

String.prototype.format = function (args) {
    var newStr = this;
    for (var key in args) {
        newStr = newStr.replace('{' + key + '}', args[key]);
    }
    return newStr;
}

Đây là một ví dụ sử dụng ...

alert("Hello {name}".format({ name: 'World' }));

8

Sử dụng trình duyệt hiện đại, hỗ trợ EcmaScript 2015 (ES6), bạn có thể thưởng thức Chuỗi mẫu . Thay vì định dạng, bạn có thể trực tiếp đưa giá trị biến vào đó:

var name = "Waleed";
var message = `Hello ${name}!`;

Lưu ý chuỗi mẫu phải được viết bằng back-ticks (`).


6

Không có câu trả lời nào được trình bày cho đến nay không có tối ưu hóa rõ ràng về việc sử dụng bao vây để khởi tạo một lần và lưu trữ các biểu thức chính quy, cho các lần sử dụng tiếp theo.

// DBJ.ORG string.format function
// usage:   "{0} means 'zero'".format("nula") 
// returns: "nula means 'zero'"
// place holders must be in a range 0-99.
// if no argument given for the placeholder, 
// no replacement will be done, so
// "oops {99}".format("!")
// returns the input
// same placeholders will be all replaced 
// with the same argument :
// "oops {0}{0}".format("!","?")
// returns "oops !!"
//
if ("function" != typeof "".format) 
// add format() if one does not exist already
  String.prototype.format = (function() {
    var rx1 = /\{(\d|\d\d)\}/g, rx2 = /\d+/ ;
    return function() {
        var args = arguments;
        return this.replace(rx1, function($0) {
            var idx = 1 * $0.match(rx2)[0];
            return args[idx] !== undefined ? args[idx] : (args[idx] === "" ? "" : $0);
        });
    }
}());

alert("{0},{0},{{0}}!".format("{X}"));

Ngoài ra, không có ví dụ nào tôn trọng việc thực hiện định dạng () nếu đã tồn tại.


2
rx2 là không cần thiết, xem triển khai của tôi; bạn có (dấu ngoặc đơn) trong rx1, nhưng không sử dụng giá trị mà chúng chuyển đến hàm bên trong. Ngoài ra, tôi nghĩ rằng đây là một tối ưu hóa rõ ràng để làm trong công cụ Javascript . Bạn có chắc chắn các trình duyệt hiện đại chưa thực hiện tối ưu hóa này đằng sau hậu trường không? Perl đã làm như vậy vào năm 1990. Bạn đã đúng rằng cần có một trình bao bọc xung quanh hàm để kiểm tra xem nó đã được thực hiện chưa.
gpvos

1
Ngoài ra, thử nghiệm trên (args [idx] === "") có vẻ không cần thiết đối với tôi: nó đã được bao phủ bởi thử nghiệm đầu tiên trên dòng đó, vì không xác định! == "".
gpvos

4

Đây là của tôi:

String.format = function(tokenised){
        var args = arguments;
        return tokenised.replace(/{[0-9]}/g, function(matched){
            matched = matched.replace(/[{}]/g, "");
            return args[parseInt(matched)+1];             
        });
    }

Không phải bằng chứng đạn nhưng hoạt động nếu bạn sử dụng nó hợp lý.


4

Đã qua mùa giải muộn nhưng tôi chỉ nhìn vào những câu trả lời được đưa ra và có giá trị tuppence của tôi:

Sử dụng:

var one = strFormat('"{0}" is not {1}', 'aalert', 'defined');
var two = strFormat('{0} {0} {1} {2}', 3.14, 'a{2}bc', 'foo');

Phương pháp:

function strFormat() {
    var args = Array.prototype.slice.call(arguments, 1);
    return arguments[0].replace(/\{(\d+)\}/g, function (match, index) {
        return args[index];
    });
}

Kết quả:

"aalert" is not defined
3.14 3.14 a{2}bc foo

3

Bây giờ bạn có thể sử dụng Mẫu chữ :

var w = "the Word";
var num1 = 2;
var num2 = 3;

var long_multiline_string = `This is very long
multiline templete string. Putting somthing here:
${w}
I can even use expresion interpolation:
Two add three = ${num1 + num2}
or use Tagged template literals
You need to enclose string with the back-tick (\` \`)`;

console.log(long_multiline_string);


3
Tôi rất hào hứng với các mẫu chữ cho đến khi tôi thấy rằng chúng chỉ hoạt động khi chuỗi được xác định cùng với các biến thay thế. Đối với tôi điều đó làm cho họ khá nhiều vô dụng; vì lý do này hay lý do khác, hầu hết các chuỗi của tôi được xác định tách biệt với mã cư trú / sử dụng chúng.
đá

2

Đây là phiên bản của tôi có thể thoát '{' và dọn sạch những người giữ chỗ không được chỉ định đó.

function getStringFormatPlaceHolderRegEx(placeHolderIndex) {
    return new RegExp('({)?\\{' + placeHolderIndex + '\\}(?!})', 'gm')
}

function cleanStringFormatResult(txt) {
    if (txt == null) return "";

    return txt.replace(getStringFormatPlaceHolderRegEx("\\d+"), "");
}

String.prototype.format = function () {
    var txt = this.toString();
    for (var i = 0; i < arguments.length; i++) {
        var exp = getStringFormatPlaceHolderRegEx(i);
        txt = txt.replace(exp, (arguments[i] == null ? "" : arguments[i]));
    }
    return cleanStringFormatResult(txt);
}
String.format = function () {
    var s = arguments[0];
    if (s == null) return "";

    for (var i = 0; i < arguments.length - 1; i++) {
        var reg = getStringFormatPlaceHolderRegEx(i);
        s = s.replace(reg, (arguments[i + 1] == null ? "" : arguments[i + 1]));
    }
    return cleanStringFormatResult(s);
}

2

Câu trả lời sau đây có lẽ là hiệu quả nhất nhưng có sự cảnh báo chỉ phù hợp với 1 đến 1 ánh xạ đối số. Điều này sử dụng cách nối chuỗi nhanh nhất (tương tự như trình tạo chuỗi: mảng chuỗi, đã nối). Đây là mã của riêng tôi. Có lẽ cần một dải phân cách tốt hơn mặc dù.

String.format = function(str, args)
{
    var t = str.split('~');
    var sb = [t[0]];
    for(var i = 0; i < args.length; i++){
        sb.push(args[i]);
        sb.push(t[i+1]);
    }
    return sb.join("");
}

Sử dụng nó như:

alert(String.format("<a href='~'>~</a>", ["one", "two"]));

2
Câu trả lời được chấp nhận là câu trả lời tốt nhất. Tôi đang đưa ra một câu trả lời duy nhất hữu ích trong các tình huống mà bạn muốn siết chặt mọi bit hiệu quả có thể (các vòng lặp dài) và bạn có ánh xạ 1: 1 của các đối số. Cuz hiệu quả hơn thay thế () và Regex mới () cùng với việc thực hiện regex chắc chắn sử dụng nhiều chu kỳ CPU hơn so với phân chia đơn ().
Skychan

Không cần -1. Không, nó không được áp dụng rộng rãi, nhưng anh ấy đúng, điều này sẽ hiệu quả hơn một chút. Bây giờ, với tác giả, một câu hỏi về kiến ​​trúc: loại ứng dụng nào sẽ xử lý một tập dữ liệu lớn như vậy trên máy khách mà loại tối ưu hóa này sẽ được yêu cầu?
Michael Blackburn

Điểm tốt Michael Blackburn. Hầu hết các tình huống có lẽ là tốt. Trong trường hợp của tôi, tôi đã xử lý một khối dữ liệu tốt (các biến thể sản phẩm trong một nhóm sản phẩm, vì vậy có thể có hàng trăm biến thể) và ý kiến ​​của tôi là vì người dùng thường mở nhiều tab trình duyệt và mọi trang web có xu hướng hút rất nhiều CPU mà Tôi thích thực hiện này để duy trì hiệu quả cao.
Skychan

2

Điều này vi phạm nguyên tắc DRY, nhưng đó là một giải pháp ngắn gọn:

var button = '<a href="{link}" class="btn">{text}</a>';
button = button.replace('{text}','Authorize on GitHub').replace('{link}', authorizeUrl);

0
<html>
<body>
<script type="text/javascript">
   var str="http://xyz.html?ID={0}&TId={1}&STId={2}&RId={3},14,480,3,38";
   document.write(FormatString(str));
   function FormatString(str) {
      var args = str.split(',');
      for (var i = 0; i < args.length; i++) {
         var reg = new RegExp("\\{" + i + "\\}", "");             
         args[0]=args[0].replace(reg, args [i+1]);
      }
      return args[0];
   }
</script>
</body>
</html>

Điều này tốt cho các URI, nhưng đối với việc sử dụng chung, có một chuỗi chứa cả định dạng và các thành phần rất dễ vỡ. Nếu chuỗi của bạn chứa dấu phẩy thì sao?
Michael Blackburn

0

Tôi không thể có được câu trả lời của Josh Stodola để làm việc, nhưng những điều sau đây có hiệu quả với tôi. Lưu ý các đặc điểm kỹ thuật của prototype. (Đã thử nghiệm trên IE, FF, Chrome và Safari.):

String.prototype.format = function() {
    var s = this;
    if(t.length - 1 != args.length){
        alert("String.format(): Incorrect number of arguments");
    }
    for (var i = 0; i < arguments.length; i++) {       
        var reg = new RegExp("\\{" + i + "\\}", "gm");
        s = s.replace(reg, arguments[i]);
    }
    return s;
}

sthực sự phải là một bản sao của thisnhư vậy là không phải là một phương pháp phá hoại, nhưng nó không phải là thực sự cần thiết.


Nó không phải là một phương pháp phá hoại. Khi s được gán lại với giá trị trả về của s.replace (), điều này vẫn chưa được xử lý.
gpvos

0

Mở rộng câu trả lời tuyệt vời của adamJLev ở trên , đây là phiên bản TypeScript:

// Extending String prototype
interface String {
    format(...params: any[]): string;
}

// Variable number of params, mimicking C# params keyword
// params type is set to any so consumer can pass number
// or string, might be a better way to constraint types to
// string and number only using generic?
String.prototype.format = function (...params: any[]) {
    var s = this,
        i = params.length;

    while (i--) {
        s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), params[i]);
    }

    return s;
};

0

Tôi có một plunker thêm nó vào nguyên mẫu chuỗi: string.format Nó không chỉ ngắn như một số ví dụ khác, mà linh hoạt hơn rất nhiều.

Cách sử dụng tương tự như phiên bản c #:

var str2 = "Meet you on {0}, ask for {1}";
var result2 = str2.format("Friday", "Suzy"); 
//result: Meet you on Friday, ask for Suzy
//NB: also accepts an array

Ngoài ra, thêm hỗ trợ cho việc sử dụng tên và thuộc tính đối tượng

var str1 = "Meet you on {day}, ask for {Person}";
var result1 = str1.format({day: "Thursday", person: "Frank"}); 
//result: Meet you on Thursday, ask for Frank

0

Bạn cũng có thể đóng mảng với sự thay thế như thế này.

var url = '/getElement/_/_/_'.replace(/_/g, (_ => this.ar[this.i++]).bind({ar: ["invoice", "id", 1337],i: 0}))
> '/getElement/invoice/id/1337

hoặc bạn có thể thử bind

'/getElement/_/_/_'.replace(/_/g, (function(_) {return this.ar[this.i++];}).bind({ar: ["invoice", "id", 1337],i: 0}))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.