printf / String.Format에 해당하는 JavaScript


1970

C / PHP printf()또는 C # / Java 프로그래머 String.Format()( IFormatProvider.NET 용) 와 동등한 JavaScript를 찾고 있습니다.

내 기본 요구 사항은 현재 숫자에 대한 천 단위 구분 기호 형식이지만 많은 조합 (날짜 포함)을 처리하는 것이 좋습니다.

Microsoft의 Ajax 라이브러리는의 버전을 제공 String.Format()하지만 해당 프레임 워크의 전체 오버 헤드를 원하지 않습니다.


2
아래의 모든 훌륭한 답변 외에도이 문제를 살펴볼 수 있습니다. stackoverflow.com/a/2648463/1712065 어떤 IMO 가이 문제에 대한 가장 효율적인 솔루션입니다.
애니

1
C와 같은 printf 구문을 사용 하는 저렴한 것을 썼습니다 .
Braden Best

var search = [$ scope.dog, "1"]; var url = vsprintf ( " earth / Services / dogSearch.svc / FindMe / % s / % s ", 검색); *** 노드의 경우, "npm install sprintf-js"를 통해 모듈을 얻을 수 있습니다
Jenna Leaf

나는 이것을 달성하기 위해 간단한 함수를 작성했다. stackoverflow.com/a/54345052/5927126
AnandShanbhag

답변:


1109

ES6부터는 템플릿 문자열을 사용할 수 있습니다.

let soMany = 10;
console.log(`This is ${soMany} times easier!`);
// "This is 10 times easier!

자세한 내용은 아래 의 Kim 답변을 참조하십시오.


그렇지 않으면:

JavaScript는 sprintf () 사용해보십시오 .


실제로 간단한 형식 방법을 원한다면 교체를 연속적으로 수행하지 말고 동시에 수행하십시오.

이전의 대체 문자열이 다음과 같은 형식 순서를 포함 할 때 언급 된 대부분의 다른 제안이 실패하기 때문에 :

"{0}{1}".format("{1}", "{0}")

일반적으로 출력은 예상 {1}{0}되지만 실제 출력은 {1}{1}입니다. 따라서 fearphage의 제안 에서와 같이 동시에 교체하십시오 .


16
간단한 숫자-문자열 변환 만 필요한 경우 num.toFixed()방법으로 충분할 수 있습니다!
heltonbiker

@MaksymilianMajer 매우 다른 것 같습니다.
Evan Carroll

@EvanCarroll 당신이 맞아요. 당시에는 리포지토리를 sprintf() for JavaScript사용할 수 없다는 의견을 썼습니다 . 구현 underscore.string기반의 sprintf 외에도 더 많은 기능이 있습니다 sprintf() for JavaScript. 그 외에 도서관은 완전히 다른 프로젝트입니다.
Maksymilian Majer

@MaksymilianMajer 맞아요.이 답변이 죽었다고 말하고 링크가 쇠퇴했습니다. 완전히 제거해야합니다.
Evan Carroll

2
더 이상 답변을 받아 들일 수 없습니다. ES6부터는 자바 스크립트 언어 (브라우저 및 NodeJS 모두)에 내장되어 있습니다. 아래 @Kim의 답변을 참조하십시오.
Ryan Shillington

1390

이전에 제안 된 솔루션을 기반으로 :

// First, checks if it isn't implemented yet.
if (!String.prototype.format) {
  String.prototype.format = function() {
    var args = arguments;
    return this.replace(/{(\d+)}/g, function(match, number) { 
      return typeof args[number] != 'undefined'
        ? args[number]
        : match
      ;
    });
  };
}

"{0} is dead, but {1} is alive! {0} {2}".format("ASP", "ASP.NET")

출력

ASP는 죽었지 만 ASP.NET은 살아 있습니다! ASP {2}


String의 프로토 타입 을 수정하지 않으려는 경우 :

if (!String.format) {
  String.format = function(format) {
    var args = Array.prototype.slice.call(arguments, 1);
    return format.replace(/{(\d+)}/g, function(match, number) { 
      return typeof args[number] != 'undefined'
        ? args[number] 
        : match
      ;
    });
  };
}

훨씬 더 친숙합니다.

String.format('{0} is dead, but {1} is alive! {0} {2}', 'ASP', 'ASP.NET');

같은 결과로 :

ASP는 죽었지 만 ASP.NET은 살아 있습니다! ASP {2}


12
|| args [number]가 0이면 트릭이 작동하지 않습니다. (args [number] === undefined)인지 확인하려면 명시적인 if ()를 수행해야합니다.
fserb

4
속기의 else 문에서 " '{'+ number + '}'"대신 "match"를 수행하는 것이 어떻습니까? 일치는 해당 문자열과 같아야합니다.
mikeycgto

4
+-operator를 사용하여 서로 연결된 문자열이 여러 개인 경우 완전한 문자열을 괄호 안에 넣어야합니다. ("asd {0}"+"fas {1}").format("first", "second");그렇지 않으면 함수는 마지막에 추가 된 문자열에만 적용됩니다.
루카스 크 누스

3
결과가 약간 미묘하게 바뀝니다. 상상해보십시오 'foo {0}'.format(fnWithNoReturnValue()). 현재 반환 foo {0}합니다. 변경하면을 반환 foo undefined합니다.
fearphage

2
@avenmore : / \ {(\ d +) \} / g
Hozuki

491

Stack Overflow에는 실제로 String라는 프로토 타입에 대한 자체 서식 기능이 있기 때문에 재미 formatUnicorn있습니다. 시도 해봐! 콘솔로 이동하여 다음과 같이 입력하십시오.

"Hello, {name}, are you feeling {adjective}?".formatUnicorn({name:"Gabriel", adjective: "OK"});

개똥 벌레

이 출력을 얻습니다.

Hello, Gabriel, are you feeling OK?

객체, 배열 및 문자열을 인수로 사용할 수 있습니다! 코드를 가져 와서 새 버전의 버전을 생성하기 위해 다시 작업했습니다 String.prototype.format.

String.prototype.formatUnicorn = String.prototype.formatUnicorn ||
function () {
    "use strict";
    var str = this.toString();
    if (arguments.length) {
        var t = typeof arguments[0];
        var key;
        var args = ("string" === t || "number" === t) ?
            Array.prototype.slice.call(arguments)
            : arguments[0];

        for (key in args) {
            str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
        }
    }

    return str;
};

영리한 Array.prototype.slice.call(arguments)호출에 주목하십시오. 즉, 단일 JSON 스타일 객체가 아닌 문자열 또는 숫자 인수를 던지면 C #의 String.Format동작이 거의 정확하게 나타납니다.

"a{0}bcd{1}ef".formatUnicorn("foo", "bar"); // yields "aFOObcdBARef"

때문에의 그 Array들 ' slice에서의 어떤 강제 argumentsArray원래 아닌지 여부, 그리고이 key때문에, 예를 들어, "0"(문자열 강요 각 배열 요소의 인덱스 (0, 1, 2, ...)입니다 "\\{0\\}"첫 정규 표현식 패턴).

산뜻한.


402
stackoverflow의 코드를 사용하여 stackoverflow에 대한 질문에 대답하는 것이
좋습니다.

5
@JamesManning 정규식은 전역 g키 ( )를 허용하며 , 동일한 키를 두 번 이상 바꿀 수 있습니다. 위의 예 {name}에서, 같은 문장에서 여러 번 사용할 수 있으며 모든 문장을 대체 할 수 있습니다 .
KrekkieD

3
솔직히 말해서 끔찍하게 깨지기 쉬운 것 같습니다. 하면 어떻게 예를 들어 일이 name있다 "blah {adjective} blah"?
sam hocevar

5
@ruffin“약간의 쌍곡선”? 사용자 데이터를 형식 문자열로 해석하는 데 사용되는 코드는 전체 취약점 범주입니다 . 98.44 %가 평범하지 않습니다 .
sam hocevar

3
@samhocevar 나는 당신에게 Little Bobby Tabled를 믿을 수 없습니다. ;) 안전 검사없이 데이터베이스 서버에서 클라이언트 측 JavaScript로 처리 된 텍스트를 실행하는 경우 천국은 우리 모두를 도와줍니다. ; ^)보세요. 사용자가 서버의 보안을 벗어나는 클라이언트 (예 : Postman)로부터 사용자가 보낼 수 있는 것은 없어야합니다. 그리고 당신은 해야 클라이언트에서 전송 될 수있는 위험한 것을 가정 수있다. 즉, 항상 사용자가 편집 할 수 있는 클라이언트 측 JavaScript 코드에서 100 % 안전이 필요 하고이 기능이 보안 위험을 초래할 수 있다고 생각하면 잘못된 게임을하고있는 것입니다.
ruffin

325

JavaScript에서 숫자 서식

다른 라이브러리를 도입하지 않고 JavaScript에서 숫자의 서식을 지정하는 방법을 찾고자하는이 질문 페이지에 도달했습니다 . 내가 찾은 것은 다음과 같습니다.

반올림 부동 소수점 숫자

sprintf("%.2f", num)JavaScript에서 이에 상응하는 것은 반올림으로 소수점 이하 2 자리로 num.toFixed(2)형식화 num됩니다 (그러나 Math.round아래 에 대한 @ ars265의 의견 참조).

(12.345).toFixed(2); // returns "12.35" (rounding!)
(12.3).toFixed(2); // returns "12.30" (zero padding)

지수 형태

동등한 sprintf("%.2e", num)IS num.toExponential(2).

(33333).toExponential(2); // "3.33e+4"

16 진법 및 기타 기반

기본 B의 숫자를 인쇄하려면을 시도하십시오 num.toString(B). JavaScript는베이스 2에서 36까지의 자동 변환을 지원합니다 (또한 일부 브라우저는 base64 인코딩에 대한 지원제한되어 있습니다 ).

(3735928559).toString(16); // to base 16: "deadbeef"
parseInt("deadbeef", 16); // from base 16: 3735928559

참조 페이지

JS 번호 형식에 대한 빠른 자습서

toFixed ()에 대한 Mozilla 참조 페이지 ( toPrecision (), toExponential (), toLocaleString () 등에 대한 링크 포함)


23
이상한 공백을 남기지 않고 숫자 리터럴을 괄호로 묶는 것이 더 좋지 않습니까?
rmobis

7
아마 더 나아 보일 것입니다. 그러나 내 목표는 구문 오류 트랩을 지적하는 것입니다.
rescdsk

4
구식 브라우저를 사용하거나 구식 브라우저를 지원하는 경우 일부 참고 사항은 toFixed 대신 Math.round를 사용하여 잘못 수정 된 것이 더 나은 솔루션입니다.
ars265

7
@Raphael_와 @rescdsk : ..또한 작동합니다 :33333..toExponential(2);
Peter Jaric

또는 (33333) .toExponential (2)
Jonathan

245

ES6부터는 템플릿 문자열을 사용할 수 있습니다 .

let soMany = 10;
console.log(`This is ${soMany} times easier!`);
// "This is 10 times easier!

템플릿 문자열은 (작은) 따옴표 대신 백틱으로 묶습니다.

자세한 정보 :

https://developers.google.com/web/updates/2015/01/ES6-Template-Strings

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings

참고 : 지원되는 브라우저 목록을 찾으려면 mozilla 사이트를 확인하십시오.


61
템플릿 문자열의 문제점은 i18n과 같은 문자열 테이블을 완전히 쓸모없는 것으로 사용하여 즉시 실행되는 것처럼 보입니다. 문자열을 일찍 정의 할 수 없으며 나중에 및 / 또는 반복적으로 사용할 매개 변수를 제공 할 수 없습니다.
Tustin2121

4
@ Tustin2121 변수에 할당되도록 작성되어 있지 않은 것이 맞습니다. 약간의 왜곡이 있지만 템플릿 문자열의 즉각적인 실행 경향을 함수로 숨기면 작업하기가 쉽습니다. 참조 jsfiddle.net/zvcm70pa을
inanutshellus

13
@ Tustin2121 템플릿 문자열을 사용하거나 이전 스타일 문자열 연결을 사용하는 것과 그에 대한 설탕은 차이가 없습니다. 구식 문자열 생성기를 간단한 함수로 감싸 야하며 문자열 템플릿에서도 똑같이 작동합니다. const compile = (x, y) => `I can call this template string whenever I want.. x=${x}, y=${y}`...compile(30, 20)
cchamberlain

4
이 솔루션은 변수로 전달 된 형식 문자열 (예 : 서버)에서 작동하지 않습니다.
user993954

1
@inanutshellus 템플릿 기능이 실행되는 동일한 머신에 정의되어 있으면 제대로 작동합니다. 내가 아는 한 함수를 JSON으로 전달할 수 없으므로 데이터베이스에 템플릿 함수를 저장하는 것이 좋지 않습니다.
styfle

171

jsxt, 지포

이 옵션이 더 적합합니다.

String.prototype.format = function() {
    var formatted = this;
    for (var i = 0; i < arguments.length; i++) {
        var regexp = new RegExp('\\{'+i+'\\}', 'gi');
        formatted = formatted.replace(regexp, arguments[i]);
    }
    return formatted;
};

이 옵션을 사용하면 다음과 같은 문자열을 바꿀 수 있습니다.

'The {0} is dead. Don\'t code {0}. Code {1} that is open source!'.format('ASP', 'PHP');

코드를 사용하면 두 번째 {0}이 (가) 대체되지 않습니다. ;)


3
gist.github.com/1049426 이 방법으로 예제를 업데이트했습니다. 기본 구현이 존재하는 경우 저장, 문자열 화 등을 포함하여 많은 이점이 있습니다. 정규 표현식을 제거하려고 시도했지만 전역 대체에 필요한 종류의 웰프가있었습니다. :-/
tbranyen

6
jsxt는 불행히도 GPL 라이센스를 받았습니다
AndiDog

109

이 간단한 기능을 사용합니다.

String.prototype.format = function() {
    var formatted = this;
    for( var arg in arguments ) {
        formatted = formatted.replace("{" + arg + "}", arguments[arg]);
    }
    return formatted;
};

이는 string.format과 매우 유사합니다.

"{0} is dead, but {1} is alive!".format("ASP", "ASP.NET")

1
+=formatted = this.replace("{" + arg + "}", arguments[arg]);
그럴까요

2
코드가 여전히 올바르지 않다고 생각합니다. 하나는 Filipiz가 게시 한 것과 같아야 합니다.
wenqiang

3
참고 for...in로이 코드가 예상하는대로 모든 브라우저에서 작동하지는 않습니다. 열거 가능한 모든 속성을 반복하며 일부 브라우저에는을 포함 arguments.length하고 다른 브라우저 에는 인수 자체도 전혀 포함하지 않습니다. 경우 어떤 경우 Object.prototype에 추가되고, 어떤 추가는 아마도 무리에 포함됩니다. 코드는 for대신 표준 루프를 사용해야합니다 for...in.
cHao

3
이전 교체품에 형식 문자열도 포함되어 있으면 실패합니다."{0} is dead, but {1} is alive!".format("{1}", "ASP.NET") === "ASP.NET is dead, but ASP.NET is alive!"
Gumbo

6
변수 arg는 전역입니다. 대신이 작업을 수행해야합니다.for (var arg in arguments) {
Pauan

68

들어 Node.js를의 사용자가 util.formatprintf와 같은 기능을 가지고있는 :

util.format("%s world", "Hello")

1
이것은 노드 v0.10.26부터 % x를 지원하지 않습니다
Max Krohn

폭과 정렬을 수정하거나 (예를 지원하지 않습니다 %-20s %5.2f)
FGM

이 유용한 답변을 보려면 페이지를 끝까지 스크롤해야했습니다.
도나 토

53

아무도 사용하지 않은 것에 놀랐습니다 reduce. 이것은 기본 간결하고 강력한 JavaScript 함수입니다.

ES6 (EcmaScript2015)

String.prototype.format = function() {
  return [...arguments].reduce((p,c) => p.replace(/%s/,c), this);
};

console.log('Is that a %s or a %s?... No, it\'s %s!'.format('plane', 'bird', 'SOman'));

<ES6

function interpolate(theString, argumentArray) {
    var regex = /%s/;
    var _r=function(p,c){return p.replace(regex,c);}
    return argumentArray.reduce(_r, theString);
}

interpolate("%s, %s and %s", ["Me", "myself", "I"]); // "Me, myself and I"

작동 방식 :

reduce 는 누산기와 배열의 각 요소 (왼쪽에서 오른쪽으로)에 대해 함수를 적용하여 단일 값으로 줄입니다.

var _r= function(p,c){return p.replace(/%s/,c)};

console.log(
  ["a", "b", "c"].reduce(_r, "[%s], [%s] and [%s]") + '\n',
  [1, 2, 3].reduce(_r, "%s+%s=%s") + '\n',
  ["cool", 1337, "stuff"].reduce(_r, "%s %s %s")
);


4
다음은이 방법을 사용하여 단순화 된 printf기능 을 만드는 버전입니다 . jsfiddle.net/11szrbx9
Dem Pilafian

1
그리고 여기 ES6을 사용하는 또 하나의 라인이 있습니다 :(...a) => {return a.reduce((p: string, c: any) => p.replace(/%s/, c));
dtasev

String.prototype.formatES6에서 필요 없음 : ((a,b,c)=>`${a}, ${b} and ${c}`)(...['me', 'myself', 'I'])(여러분의 예제에 더 잘 맞도록 약간 중복 됨)
Tino

printf유형 지정자 에 대해 대체 함수를 구현 하고 패딩 접두사에 대한 논리를 포함해야합니다. 합리적인 형식으로 형식 문자열을 반복하는 것이 여기에 사소한 문제인 것 같습니다. 그러나 문자열 교체 만 필요한 경우 깔끔한 솔루션입니다.
collapsar

51

JavaScript에서 sprintf 의 최소 구현은 다음과 같습니다 . "% s"및 "% d"만 수행하지만 확장 할 공간을 남겨 두었습니다. OP에는 쓸모가 없지만 Google에서이 스레드를 우연히 발견 한 다른 사람들이 혜택을 볼 수 있습니다.

function sprintf() {
    var args = arguments,
    string = args[0],
    i = 1;
    return string.replace(/%((%)|s|d)/g, function (m) {
        // m is the matched format, e.g. %s, %d
        var val = null;
        if (m[2]) {
            val = m[2];
        } else {
            val = args[i];
            // A switch statement so that the formatter can be extended. Default is %s
            switch (m) {
                case '%d':
                    val = parseFloat(val);
                    if (isNaN(val)) {
                        val = 0;
                    }
                    break;
            }
            i++;
        }
        return val;
    });
}

예:

alert(sprintf('Latitude: %s, Longitude: %s, Count: %d', 41.847, -87.661, 'two'));
// Expected output: Latitude: 41.847, Longitude: -87.661, Count: 0

이전 답변의 유사한 솔루션과 달리이 방법은 한 번에 모든 대체 를 수행 하므로 이전에 대체 된 값의 일부를 대체하지 않습니다.



24

zippoxer답변에 추가하면 이 기능을 사용합니다.

String.prototype.format = function () {
    var a = this, b;
    for (b in arguments) {
        a = a.replace(/%[a-z]/, arguments[b]);
    }
    return a; // Make chainable
};

var s = 'Hello %s The magic number is %d.';
s.format('world!', 12); // Hello World! The magic number is 12.

또한 Java와 유사한 구문에 더 자주 사용하는 비 프로토 타입 버전이 있습니다.

function format() {
    var a, b, c;
    a = arguments[0];
    b = [];
    for(c = 1; c < arguments.length; c++){
        b.push(arguments[c]);
    }
    for (c in b) {
        a = a.replace(/%[a-z]/, b[c]);
    }
    return a;
}
format('%d ducks, 55 %s', 12, 'cats'); // 12 ducks, 55 cats

ES 2015 업데이트

ES 2015의 모든 멋진 새 기능을 사용하면이 작업이 훨씬 쉬워집니다.

function format(fmt, ...args){
    return fmt
        .split("%%")
        .reduce((aggregate, chunk, i) =>
            aggregate + chunk + (args[i] || ""), "");
}

format("Hello %%! I ate %% apples today.", "World", 44);
// "Hello World, I ate 44 apples today."

나는 이것이 오래된 것과 마찬가지로 실제로 문자를 파싱하지 않기 때문에 단일 토큰 만 사용할 수도 있다고 생각했습니다 %%. 이것은 명백하고 단일을 사용하는 것을 어렵게하지 않는 이점이 있습니다 %. 그러나 %%어떤 이유로 든 필요한 경우 자체로 교체해야합니다.

format("I love percentage signs! %%", "%%");
// "I love percentage signs! %%"

3
이 답변은 기존 기능에 빠른 복사 붙여 넣기에 유용했습니다. 다운로드 등이 필요 없음
Nick

@Nick yep, 그 아이디어입니다 :)
Braden Best

21

함수 본문이 아래와 같거나 매 반복마다 현재 문자열을 추가한다는 점을 제외하고 Zippo +1

String.prototype.format = function() {
    var formatted = this;
    for (var arg in arguments) {
        formatted = formatted.replace("{" + arg + "}", arguments[arg]);
    }
    return formatted;
};

1
Firefox에서는 작동하지 않았습니다. 디버거는 arg를 정의되지 않은 것으로 표시합니다.
xiao 啸

'The {0} is dead. Don\'t code {0}. Code {1} that is open source!'.format('ASP', 'PHP'); 결과가 되는 두 번째 문자를 대체하지 않습니다 The ASP is dead. Don't code {0}. Code PHP that is open source!. for(arg in arguments)IE에서 한 가지 더 작동하지 않습니다. for (arg = 0; arg <arguments.length; arg++)
samarjit samanta

2
참고 for...in로이 코드가 예상하는대로 모든 브라우저에서 작동하지는 않습니다. 열거 가능한 모든 속성을 반복하며 일부 브라우저에는을 포함 arguments.length하고 다른 브라우저 에는 인수 자체도 전혀 포함하지 않습니다. 경우 어떤 경우 Object.prototype에 추가되고, 어떤 추가는 아마도 무리에 포함됩니다. 코드는 for대신 표준 루프를 사용해야합니다 for...in.
cHao

중복 답변 대신 답변 편집을 제안해야합니다. 이것은 이 답변을
RousseauAlexandre

19

'문제'에 대한 솔루션을 공유하고 싶습니다. 휠을 다시 발명하지는 않았지만 JavaScript가 이미 수행 한 작업을 기반으로 솔루션을 찾으려고합니다. 장점은 모든 암시 적 변환을 무료로 얻을 수 있다는 것입니다. String의 프로토 타입 속성 $를 설정하면 매우 훌륭하고 간단한 구문이 제공됩니다 (아래 예 참조). 아마도 가장 효율적인 방법은 아니지만 대부분의 경우 출력을 처리 할 때 반드시 최적화 할 필요는 없습니다.

String.form = function(str, arr) {
    var i = -1;
    function callback(exp, p0, p1, p2, p3, p4) {
        if (exp=='%%') return '%';
        if (arr[++i]===undefined) return undefined;
        exp  = p2 ? parseInt(p2.substr(1)) : undefined;
        var base = p3 ? parseInt(p3.substr(1)) : undefined;
        var val;
        switch (p4) {
            case 's': val = arr[i]; break;
            case 'c': val = arr[i][0]; break;
            case 'f': val = parseFloat(arr[i]).toFixed(exp); break;
            case 'p': val = parseFloat(arr[i]).toPrecision(exp); break;
            case 'e': val = parseFloat(arr[i]).toExponential(exp); break;
            case 'x': val = parseInt(arr[i]).toString(base?base:16); break;
            case 'd': val = parseFloat(parseInt(arr[i], base?base:10).toPrecision(exp)).toFixed(0); break;
        }
        val = typeof(val)=='object' ? JSON.stringify(val) : val.toString(base);
        var sz = parseInt(p1); /* padding size */
        var ch = p1 && p1[0]=='0' ? '0' : ' '; /* isnull? */
        while (val.length<sz) val = p0 !== undefined ? val+ch : ch+val; /* isminus? */
       return val;
    }
    var regex = /%(-)?(0?[0-9]+)?([.][0-9]+)?([#][0-9]+)?([scfpexd%])/g;
    return str.replace(regex, callback);
}

String.prototype.$ = function() {
    return String.form(this, Array.prototype.slice.call(arguments));
}

다음은 몇 가지 예입니다.

String.format("%s %s", [ "This is a string", 11 ])
console.log("%s %s".$("This is a string", 11))
var arr = [ "12.3", 13.6 ]; console.log("Array: %s".$(arr));
var obj = { test:"test", id:12 }; console.log("Object: %s".$(obj));
console.log("%c", "Test");
console.log("%5d".$(12)); // '   12'
console.log("%05d".$(12)); // '00012'
console.log("%-5d".$(12)); // '12   '
console.log("%5.2d".$(123)); // '  120'
console.log("%5.2f".$(1.1)); // ' 1.10'
console.log("%10.2e".$(1.1)); // '   1.10e+0'
console.log("%5.3p".$(1.12345)); // ' 1.12'
console.log("%5x".$(45054)); // ' affe'
console.log("%20#2x".$("45054")); // '    1010111111111110'
console.log("%6#2d".$("111")); // '     7'
console.log("%6#16d".$("affe")); // ' 45054'

불행히도 적어도 #과 +는 float에 대해 구현되지 않습니다. 다음은 c의 함수에 대한 참조입니다. tutorialspoint.com/c_standard_library/c_function_sprintf.htm
Daniel


14

대부분의 형식 문자열 기능 (숫자 및 날짜 형식 포함)을 지원하고 .NET 구문을 사용하는 JavaScript 용 String.format 이라는 작은 라이브러리를 사용합니다. 스크립트 자체는 4kB보다 작으므로 오버 헤드가 많이 발생하지 않습니다.


나는 그 도서관을 보았는데 정말 좋아 보인다. 다운로드가 EXE 인 것을 보았을 때 화가났습니다. 도대체 뭐야? 다운로드하지 않았습니다.
jessegavin

EXE 인 다운로드 가능한 아카이브는 종종 "자동 압축 풀기 ZIP"에 지나지 않습니다. 그것을 실행하면 압축이 풀립니다. 이것은 매우 편리하지만 맬웨어와 매우 유사하기 때문에 웹에서 더 이상 형식이 사용되지 않습니다.
Chuck Kollars

이 링크가 질문에 대한 답변을 제공 할 수 있지만 여기에 답변의 필수 부분을 포함시키고 참조 용 링크를 제공하는 것이 좋습니다. 링크 된 페이지가 변경되면 링크 전용 답변이 유효하지 않을 수 있습니다.
starmole 2016 년

@starmole 링크는 (최소화 된) 4 kB 자바 스크립트 라이브러리 입니다. 나는 그것을 대답에 붙여 넣는 것이 좋은 생각이라고 믿지 않습니다.
ivarni 2016 년

붙여 넣는 것이 낫지 않을 것입니다. 방금 임의의 검토를 위해이 의견을 얻었습니다. 나에게 스택 오버 플로우는 준비된 솔루션 (링크)보다는 설명을 제공 할 때 더 좋습니다. 또한 사람들이 블랙 박스 코드를 게시하거나 다운로드하도록 장려하고 싶지 않습니다.
starmole 2016 년

14

매우 우아함 :

String.prototype.format = function (){
    var args = arguments;
    return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (curlyBrack, index) {
        return ((curlyBrack == "{{") ? "{" : ((curlyBrack == "}}") ? "}" : args[index]));
    });
};

// Usage:
"{0}{1}".format("{1}", "{0}")

신용은 (깨진 링크) https://gist.github.com/0i0/1519811


이스케이프 대괄호 {{0}}와 같은 것을 처리하는 유일한 것입니다 {0}{1}.format("{1}", "{0}"). 맨 위에 있어야합니다!
Juan

11

천 단위 구분 기호를 처리하려면 JavaScript Number 클래스 에서 toLocaleString ()을 사용해야 합니다. 사용자 지역의 문자열 형식을 지정하기 때문입니다.

JavaScript Date 클래스는 현지화 된 날짜 및 시간의 형식을 지정할 수 있습니다.


1
실제로 사용자가 응용 프로그램의 설정으로 설정 한 것이지만 (기계가 아닌) 감사합니다.
Chris S

모든 사람들이 신속하게 이해할 수 있도록 몇 가지 예를 추가하십시오.
Bhushan Kawadkar


9

나는 이것을 사용한다 :

String.prototype.format = function() {
    var newStr = this, i = 0;
    while (/%s/.test(newStr))
        newStr = newStr.replace("%s", arguments[i++])

    return newStr;
}

그런 다음 호출합니다.

"<h1>%s</h1><p>%s</p>".format("Header", "Just a test!");

9

Peter와 매우 가까운 솔루션이 있지만 숫자와 객체 사례를 처리합니다.

if (!String.prototype.format) {
  String.prototype.format = function() {
    var args;
    args = arguments;
    if (args.length === 1 && args[0] !== null && typeof args[0] === 'object') {
      args = args[0];
    }
    return this.replace(/{([^}]*)}/g, function(match, key) {
      return (typeof args[key] !== "undefined" ? args[key] : match);
    });
  };
}

어쩌면 모든 심층 사건을 다루는 것이 더 나을 수도 있지만, 내 필요에 따라 이것은 괜찮습니다.

"This is an example from {name}".format({name:"Blaine"});
"This is an example from {0}".format("Blaine");

추신 : AngularJS 와 같은 템플릿 프레임 워크에서 번역을 사용하는 경우이 기능은 매우 좋습니다 .

<h1> {{('hello-message'|translate).format(user)}} <h1>
<h1> {{('hello-by-name'|translate).format( user ? user.name : 'You' )}} <h1>

en.json과 같은 곳

{
    "hello-message": "Hello {name}, welcome.",
    "hello-by-name": "Hello {0}, welcome."
}

정규 표현식의 [^}] 부분은 필요하지 않습니다. 대신 {(. *?)}를 사용하거나 더 나은 {([\ s \ S] *?)}를 사용하여 줄 바꿈도 일치 시키십시오.
rawiro

7

매우 선호하는 버전 중 하나는 내가 선호하는 버전입니다 (이 버전은 {0} 번호가 매겨진 인수가 아닌 {xxx} 토큰을 사용합니다.이 방법은 훨씬 더 자체 문서화되어 있으며 현지화에 훨씬 적합합니다).

String.prototype.format = function(tokens) {
  var formatted = this;
  for (var token in tokens)
    if (tokens.hasOwnProperty(token))
      formatted = formatted.replace(RegExp("{" + token + "}", "g"), tokens[token]);
  return formatted;
};

변형은 다음과 같습니다.

  var formatted = l(this);

먼저 l () 지역화 함수를 호출합니다.



6

Node.JS 와 그 util.format기능 을 좋아하는 사람들을 위해 방금 JavaScript를 util.format에서 사용하는 함수만으로 바닐라 JavaScript 형식으로 추출했습니다.

exports = {};

function isString(arg) {
    return typeof arg === 'string';
}
function isNull(arg) {
    return arg === null;
}
function isObject(arg) {
    return typeof arg === 'object' && arg !== null;
}
function isBoolean(arg) {
    return typeof arg === 'boolean';
}
function isUndefined(arg) {
    return arg === void 0;
}
function stylizeNoColor(str, styleType) {
    return str;
}
function stylizeWithColor(str, styleType) {
    var style = inspect.styles[styleType];

    if (style) {
        return '\u001b[' + inspect.colors[style][0] + 'm' + str +
            '\u001b[' + inspect.colors[style][3] + 'm';
    } else {
        return str;
    }
}
function isFunction(arg) {
    return typeof arg === 'function';
}
function isNumber(arg) {
    return typeof arg === 'number';
}
function isSymbol(arg) {
    return typeof arg === 'symbol';
}
function formatPrimitive(ctx, value) {
    if (isUndefined(value))
        return ctx.stylize('undefined', 'undefined');
    if (isString(value)) {
        var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
                .replace(/'/g, "\\'")
                .replace(/\\"/g, '"') + '\'';
        return ctx.stylize(simple, 'string');
    }
    if (isNumber(value)) {
        // Format -0 as '-0'. Strict equality won't distinguish 0 from -0,
        // so instead we use the fact that 1 / -0 < 0 whereas 1 / 0 > 0 .
        if (value === 0 && 1 / value < 0)
            return ctx.stylize('-0', 'number');
        return ctx.stylize('' + value, 'number');
    }
    if (isBoolean(value))
        return ctx.stylize('' + value, 'boolean');
    // For some reason typeof null is "object", so special case here.
    if (isNull(value))
        return ctx.stylize('null', 'null');
    // es6 symbol primitive
    if (isSymbol(value))
        return ctx.stylize(value.toString(), 'symbol');
}
function arrayToHash(array) {
    var hash = {};

    array.forEach(function (val, idx) {
        hash[val] = true;
    });

    return hash;
}
function objectToString(o) {
    return Object.prototype.toString.call(o);
}
function isDate(d) {
    return isObject(d) && objectToString(d) === '[object Date]';
}
function isError(e) {
    return isObject(e) &&
        (objectToString(e) === '[object Error]' || e instanceof Error);
}
function isRegExp(re) {
    return isObject(re) && objectToString(re) === '[object RegExp]';
}
function formatError(value) {
    return '[' + Error.prototype.toString.call(value) + ']';
}
function formatPrimitiveNoColor(ctx, value) {
    var stylize = ctx.stylize;
    ctx.stylize = stylizeNoColor;
    var str = formatPrimitive(ctx, value);
    ctx.stylize = stylize;
    return str;
}
function isArray(ar) {
    return Array.isArray(ar);
}
function hasOwnProperty(obj, prop) {
    return Object.prototype.hasOwnProperty.call(obj, prop);
}
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
    var name, str, desc;
    desc = Object.getOwnPropertyDescriptor(value, key) || {value: value[key]};
    if (desc.get) {
        if (desc.set) {
            str = ctx.stylize('[Getter/Setter]', 'special');
        } else {
            str = ctx.stylize('[Getter]', 'special');
        }
    } else {
        if (desc.set) {
            str = ctx.stylize('[Setter]', 'special');
        }
    }
    if (!hasOwnProperty(visibleKeys, key)) {
        name = '[' + key + ']';
    }
    if (!str) {
        if (ctx.seen.indexOf(desc.value) < 0) {
            if (isNull(recurseTimes)) {
                str = formatValue(ctx, desc.value, null);
            } else {
                str = formatValue(ctx, desc.value, recurseTimes - 1);
            }
            if (str.indexOf('\n') > -1) {
                if (array) {
                    str = str.split('\n').map(function (line) {
                        return '  ' + line;
                    }).join('\n').substr(2);
                } else {
                    str = '\n' + str.split('\n').map(function (line) {
                        return '   ' + line;
                    }).join('\n');
                }
            }
        } else {
            str = ctx.stylize('[Circular]', 'special');
        }
    }
    if (isUndefined(name)) {
        if (array && key.match(/^\d+$/)) {
            return str;
        }
        name = JSON.stringify('' + key);
        if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
            name = name.substr(1, name.length - 2);
            name = ctx.stylize(name, 'name');
        } else {
            name = name.replace(/'/g, "\\'")
                .replace(/\\"/g, '"')
                .replace(/(^"|"$)/g, "'")
                .replace(/\\\\/g, '\\');
            name = ctx.stylize(name, 'string');
        }
    }

    return name + ': ' + str;
}
function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
    var output = [];
    for (var i = 0, l = value.length; i < l; ++i) {
        if (hasOwnProperty(value, String(i))) {
            output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
                String(i), true));
        } else {
            output.push('');
        }
    }
    keys.forEach(function (key) {
        if (!key.match(/^\d+$/)) {
            output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
                key, true));
        }
    });
    return output;
}
function reduceToSingleString(output, base, braces) {
    var length = output.reduce(function (prev, cur) {
        return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
    }, 0);

    if (length > 60) {
        return braces[0] +
            (base === '' ? '' : base + '\n ') +
            ' ' +
            output.join(',\n  ') +
            ' ' +
            braces[1];
    }

    return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
}
function formatValue(ctx, value, recurseTimes) {
    // Provide a hook for user-specified inspect functions.
    // Check that value is an object with an inspect function on it
    if (ctx.customInspect &&
        value &&
        isFunction(value.inspect) &&
            // Filter out the util module, it's inspect function is special
        value.inspect !== exports.inspect &&
            // Also filter out any prototype objects using the circular check.
        !(value.constructor && value.constructor.prototype === value)) {
        var ret = value.inspect(recurseTimes, ctx);
        if (!isString(ret)) {
            ret = formatValue(ctx, ret, recurseTimes);
        }
        return ret;
    }

    // Primitive types cannot have properties
    var primitive = formatPrimitive(ctx, value);
    if (primitive) {
        return primitive;
    }

    // Look up the keys of the object.
    var keys = Object.keys(value);
    var visibleKeys = arrayToHash(keys);

    if (ctx.showHidden) {
        keys = Object.getOwnPropertyNames(value);
    }

    // This could be a boxed primitive (new String(), etc.), check valueOf()
    // NOTE: Avoid calling `valueOf` on `Date` instance because it will return
    // a number which, when object has some additional user-stored `keys`,
    // will be printed out.
    var formatted;
    var raw = value;
    try {
        // the .valueOf() call can fail for a multitude of reasons
        if (!isDate(value))
            raw = value.valueOf();
    } catch (e) {
        // ignore...
    }

    if (isString(raw)) {
        // for boxed Strings, we have to remove the 0-n indexed entries,
        // since they just noisey up the output and are redundant
        keys = keys.filter(function (key) {
            return !(key >= 0 && key < raw.length);
        });
    }

    // Some type of object without properties can be shortcutted.
    if (keys.length === 0) {
        if (isFunction(value)) {
            var name = value.name ? ': ' + value.name : '';
            return ctx.stylize('[Function' + name + ']', 'special');
        }
        if (isRegExp(value)) {
            return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
        }
        if (isDate(value)) {
            return ctx.stylize(Date.prototype.toString.call(value), 'date');
        }
        if (isError(value)) {
            return formatError(value);
        }
        // now check the `raw` value to handle boxed primitives
        if (isString(raw)) {
            formatted = formatPrimitiveNoColor(ctx, raw);
            return ctx.stylize('[String: ' + formatted + ']', 'string');
        }
        if (isNumber(raw)) {
            formatted = formatPrimitiveNoColor(ctx, raw);
            return ctx.stylize('[Number: ' + formatted + ']', 'number');
        }
        if (isBoolean(raw)) {
            formatted = formatPrimitiveNoColor(ctx, raw);
            return ctx.stylize('[Boolean: ' + formatted + ']', 'boolean');
        }
    }

    var base = '', array = false, braces = ['{', '}'];

    // Make Array say that they are Array
    if (isArray(value)) {
        array = true;
        braces = ['[', ']'];
    }

    // Make functions say that they are functions
    if (isFunction(value)) {
        var n = value.name ? ': ' + value.name : '';
        base = ' [Function' + n + ']';
    }

    // Make RegExps say that they are RegExps
    if (isRegExp(value)) {
        base = ' ' + RegExp.prototype.toString.call(value);
    }

    // Make dates with properties first say the date
    if (isDate(value)) {
        base = ' ' + Date.prototype.toUTCString.call(value);
    }

    // Make error with message first say the error
    if (isError(value)) {
        base = ' ' + formatError(value);
    }

    // Make boxed primitive Strings look like such
    if (isString(raw)) {
        formatted = formatPrimitiveNoColor(ctx, raw);
        base = ' ' + '[String: ' + formatted + ']';
    }

    // Make boxed primitive Numbers look like such
    if (isNumber(raw)) {
        formatted = formatPrimitiveNoColor(ctx, raw);
        base = ' ' + '[Number: ' + formatted + ']';
    }

    // Make boxed primitive Booleans look like such
    if (isBoolean(raw)) {
        formatted = formatPrimitiveNoColor(ctx, raw);
        base = ' ' + '[Boolean: ' + formatted + ']';
    }

    if (keys.length === 0 && (!array || value.length === 0)) {
        return braces[0] + base + braces[1];
    }

    if (recurseTimes < 0) {
        if (isRegExp(value)) {
            return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
        } else {
            return ctx.stylize('[Object]', 'special');
        }
    }

    ctx.seen.push(value);

    var output;
    if (array) {
        output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
    } else {
        output = keys.map(function (key) {
            return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
        });
    }

    ctx.seen.pop();

    return reduceToSingleString(output, base, braces);
}
function inspect(obj, opts) {
    // default options
    var ctx = {
        seen: [],
        stylize: stylizeNoColor
    };
    // legacy...
    if (arguments.length >= 3) ctx.depth = arguments[2];
    if (arguments.length >= 4) ctx.colors = arguments[3];
    if (isBoolean(opts)) {
        // legacy...
        ctx.showHidden = opts;
    } else if (opts) {
        // got an "options" object
        exports._extend(ctx, opts);
    }
    // set default options
    if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
    if (isUndefined(ctx.depth)) ctx.depth = 2;
    if (isUndefined(ctx.colors)) ctx.colors = false;
    if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
    if (ctx.colors) ctx.stylize = stylizeWithColor;
    return formatValue(ctx, obj, ctx.depth);
}
exports.inspect = inspect;


// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
inspect.colors = {
    'bold': [1, 22],
    'italic': [3, 23],
    'underline': [4, 24],
    'inverse': [7, 27],
    'white': [37, 39],
    'grey': [90, 39],
    'black': [30, 39],
    'blue': [34, 39],
    'cyan': [36, 39],
    'green': [32, 39],
    'magenta': [35, 39],
    'red': [31, 39],
    'yellow': [33, 39]
};

// Don't use 'blue' not visible on cmd.exe
inspect.styles = {
    'special': 'cyan',
    'number': 'yellow',
    'boolean': 'yellow',
    'undefined': 'grey',
    'null': 'bold',
    'string': 'green',
    'symbol': 'green',
    'date': 'magenta',
    // "name": intentionally not styling
    'regexp': 'red'
};


var formatRegExp = /%[sdj%]/g;
exports.format = function (f) {
    if (!isString(f)) {
        var objects = [];
        for (var j = 0; j < arguments.length; j++) {
            objects.push(inspect(arguments[j]));
        }
        return objects.join(' ');
    }

    var i = 1;
    var args = arguments;
    var len = args.length;
    var str = String(f).replace(formatRegExp, function (x) {
        if (x === '%%') return '%';
        if (i >= len) return x;
        switch (x) {
            case '%s':
                return String(args[i++]);
            case '%d':
                return Number(args[i++]);
            case '%j':
                try {
                    return JSON.stringify(args[i++]);
                } catch (_) {
                    return '[Circular]';
                }
            default:
                return x;
        }
    });
    for (var x = args[i]; i < len; x = args[++i]) {
        if (isNull(x) || !isObject(x)) {
            str += ' ' + x;
        } else {
            str += ' ' + inspect(x);
        }
    }
    return str;
};

https://github.com/joyent/node/blob/master/lib/util.js 에서 수확



5

나는 자바 스크립트에 대한 약간 더 포맷터가 여기를 ...

여러 가지 형식을 지정할 수 있습니다.

  • String.format(input, args0, arg1, ...)
  • String.format(input, obj)
  • "literal".format(arg0, arg1, ...)
  • "literal".format(obj)

또한 ObjectBase.prototype.format (예 : DateJS 사용 ) 을 말하면 사용합니다.

예 ...

var input = "numbered args ({0}-{1}-{2}-{3})";
console.log(String.format(input, "first", 2, new Date()));
//Outputs "numbered args (first-2-Thu May 31 2012...Time)-{3})"

console.log(input.format("first", 2, new Date()));
//Outputs "numbered args(first-2-Thu May 31 2012...Time)-{3})"

console.log(input.format(
    "object properties ({first}-{second}-{third:yyyy-MM-dd}-{fourth})"
    ,{
        'first':'first'
        ,'second':2
        ,'third':new Date() //assumes Date.prototype.format method
    }
));
//Outputs "object properties (first-2-2012-05-31-{3})"

또한 .asFormat으로 별칭을 지정했으며 이미 string.format이있는 경우 (예 : MS Ajax Toolkit과 같은 경우) 라이브러리를 싫어합니다.


5

누군가가 전역 범위를 오염시키는 것을 방지하는 기능이 필요한 경우를 대비하여 다음과 같은 기능을 수행합니다.

  function _format (str, arr) {
    return str.replace(/{(\d+)}/g, function (match, number) {
      return typeof arr[number] != 'undefined' ? arr[number] : match;
    });
  };

3

Typescript에 간단한 경량 String.Format 문자열 작업 라이브러리를 사용할 수 있습니다 .

String.Format () :

var id = image.GetId()
String.Format("image_{0}.jpg", id)
output: "image_2db5da20-1c5d-4f1a-8fd4-b41e34c8c5b5.jpg";

지정자를위한 문자열 형식 :

var value = String.Format("{0:L}", "APPLE"); //output "apple"

value = String.Format("{0:U}", "apple"); // output "APPLE"

value = String.Format("{0:d}", "2017-01-23 00:00"); //output "23.01.2017"


value = String.Format("{0:s}", "21.03.2017 22:15:01") //output "2017-03-21T22:15:01"

value = String.Format("{0:n}", 1000000);
//output "1.000.000"

value = String.Format("{0:00}", 1);
//output "01"

지정자를 포함한 객체의 문자열 형식 :

var fruit = new Fruit();
fruit.type = "apple";
fruit.color = "RED";
fruit.shippingDate = new Date(2018, 1, 1);
fruit.amount = 10000;

String.Format("the {type:U} is {color:L} shipped on {shippingDate:s} with an amount of {amount:n}", fruit);
// output: the APPLE is red shipped on 2018-01-01 with an amount of 10.000

2

String.format변형을 보지 못했습니다 .

String.format = function (string) {
    var args = Array.prototype.slice.call(arguments, 1, arguments.length);
    return string.replace(/{(\d+)}/g, function (match, number) {
        return typeof args[number] != "undefined" ? args[number] : match;
    });
};

2

jQuery.ajax () 성공 함수와 함께 사용합니다. 하나의 인수 만 전달하면 {propertyName}과 같이 해당 객체의 속성으로 문자열을 대체합니다.

String.prototype.format = function () {
    var formatted = this;
    for (var prop in arguments[0]) {
        var regexp = new RegExp('\\{' + prop + '\\}', 'gi');
        formatted = formatted.replace(regexp, arguments[0][prop]);
    }
    return formatted;
};

예:

var userInfo = ("Email: {Email} - Phone: {Phone}").format({ Email: "someone@somewhere.com", Phone: "123-123-1234" });
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.