web-dev-qa-db-ja.com

RegExpと関数をJSONに保存できますか?

次のようなブロックがあるとします。

var foo = {"regexp":/^http:\/\//,
           "fun":function(){},
}

それをJSONに保存する適切な方法は何ですか?

22
Huang

RegExpを文字列としてJSONオブジェクトに保存する必要があります。次に、文字列からRegExpオブジェクトを作成できます。

// JSON Object (can be an imported file, of course)
// Store RegExp pattern as a string
// Double backslashes are required to put literal \ characters in the string
var jsonObject = { "regex": "^http:\\/\\/" };

function fun(url) {
    var regexp = new RegExp(jsonObject.regex, 'i');

    var match;

    // You can do either:
    match = url.match(regexp);
    // Or (useful for capturing groups when doing global search):
    match = regexp.exec(url);

    // Logic to process match results
    // ...
    return 'ooga booga boo';
}

関数については、JSONやXMLで表すべきではありません。関数はJSでオブジェクトとして定義できますが、その主な目的はコマンドのシーケンスをカプセル化することであり、基本的なデータのラッパーとしては機能しません。

35
Ankit Aggarwal

できません。 JSONはデータ専用であり、コードではありません。最初に文字列に変換できない限り、関数を転送する方法はありません。

11
Evert

あなたはこのようなことをすることができます...

方法

JSONEX = {

    stringify: function(obj){
        var jsonified = {}
        // loop through object and write string and type to newly stored data structure
        for(i in obj)
            jsonified[i] = {
                // some voodoo to determine the variable type
                type: Object.prototype.toString.call(obj[i]).split(/\W/)[2],
                value: obj[i].toString()
            }    
        return JSON.stringify(jsonified)
    },

    parse: function(json){
        objectified = {}
        obj = JSON.parse(json)
        // loop through object, and handle parsing of string according to type
        for(i in obj)
            if(obj[i].type == "RegExp"){
                var m = obj[i].value.match(/\/(.*)\/([a-z]+)?/)
                objectified[i] = new RegExp(m[1],m[2]);
            } else if(obj[i].type == "String"){
                objectified[i] = obj[i].value
            } else if(obj[i].type == "Function"){
                // WARNING: this is more or less like using eval
                // All the usual caveats apply - including jailtime
                objectified[i] = new Function("return ("+obj[i].value+")")();
            }
            // ADD MORE TYPE HANDLERS HERE ...

        return objectified

    }
}

使用法

myThing = {
    regex: new RegExp("123","g"),
    text: "good",
    func: function(x){
        return x * x
    }
}

json = JSONEX.stringify(myThing)
// "{"regex":{"type":"RegExp","value":"/123/g"},"text":{"type":"String","value":"good"},"func":{"type":"Function","value":"function (x) {\n    return x * x;\n}"}}"

obj = JSONEX.parse(json)
// native object representing original object

N.B.

ほぼ良い解決策ですが、正規表現では機能しません(とにかく私にとって)

http://jsonplus.com/

// doing this: jsonPlus.stringify(myThing)
// just stores `regex` as an empty object
7
Billy Moon

まだ答えを探している人のために:

plaginJSONfnを使用すると、JavaScriptオブジェクトをシリアル化できます

  • 機能
  • Regexp
  • 日付

この文字列からオブジェクトを再作成します。

ドキュメント: http://www.eslinstructor.net/jsonfn/

-ヴァディム

3
vadimk

コアJSONにはありません。 JSON仕様 は、プリミティブ値(string/numbers/boolean/null)、および配列とオブジェクトのみを許可します。

2
Jason S

TL; DR:

オブジェクトとして両方を保存するのが私には最良のようです:

{
    "regexp": {
        "body": "^http:\\/\\/",
        "flags": ""
    },
    "fun": {
        "args": [],
        "body": ""
    }
}

RegExps:

正規表現を保存するための素晴らしい答えはすでにたくさんあります。それらを生の文字列として保存し、 RegExp コンストラクタを使用して文字列から実際の正規表現を作成できるようにします。

私の追加はフラグを覚えておくことです。 OPはそれを必要としない場合がありますが、必ず対処する必要があります。 RegExp コンストラクターは、2番目のパラメーターとして文字列の形式のフラグを取ります。したがって、JSONに格納された正規表現のコントラクトは次のようになります。

interface JSONStoredRegExp {
    body: string; // "" (empty string) for empty regexp
    flags: string; // "" (empty string) for zero flags
}

...そして、例えば、このJSON:

{
    "regexp": {
        "body": "abc",
        "flags": "gi"
    }
}

...この正規表現を生成します:

RegExp(json.regexp.body, json.regexp.flags);
/abc/gi

関数:

与えられた関数が純粋でない限り、JSON経由で転送するのは私には奇妙に思えます。また、そのようなアルゴリズムのコードは、JavaScript以外の言語と互換性がない可能性があります。

とにかく、それが依然として必要な場合は、同じアプローチをお勧めします。文字列ではなくオブジェクトとして関数を転送します。 Function コンストラクターを使用して、引数と本文のシリアル化されたリストから関数を作成することもできます。

interface JSONStoredFunction {
    args: string[]; // [] (empty array) for zero arguments
    body: string; // "" (empty string) for no-op function
}

Function コンストラクタは最後の引数として本体を受け取り、各パラメータは個別に渡す必要があります。したがって、このJSON:

{
    "fun": {
        "args": [ "x", "y" ],
        "body": "return x + y;"
    }
}

...この関数を生成します:

Function(...json.fun.args, json.fun.body);
function anonymous(x, y) { return x + y; }

...スプレッド演算子 を使用するのは不便かもしれません。その場合、.applyを使用すると役立つ場合があります。

Function.apply(null, json.fun.args.concat(json.fun.body));
1

私は使用しており、yahooの serialize-javascript npmパッケージをお勧めします。 JSONを関数と正規表現でシリアル化し、他のケースを処理できます。

彼らのドキュメントから:

var serialize = require('serialize-javascript');

const serialized = serialize({
    str  : 'string',
    num  : 0,
    obj  : {foo: 'foo'},
    arr  : [1, 2, 3],
    bool : true,
    nil  : null,
    undef: undefined,

    fn: function echo(arg) { return arg; },
    re: /([^\s]+)/g
});

作り出す

'{"str":"string","num":0,"obj":{"foo":"foo"},"arr":[1,2,3],"bool":true,"nil":null,"fn":function echo(arg) { return arg; },"re":/([^\\s]+)/g}'

水和することができます

const obj = JSON.parse(serialized)

これは 単体テスト を確認することで確認できます。

0
cchamberlain

これはJSONではありませんが、シリアライゼーションの形式です:foo.toSource()は文字列表現を提供します:"({regexp:/^http:\\/\\//, fun:(function () {})})"bar = eval(foo.toSource());を使用すると、正規表現と関数を含む新しいオブジェクトがbarに割り当てられます。

どの程度サポートされているのかわかりません。いくつかのウェブサイトでは、2歳ですが、これはgeckoのみであると述べています。私は現在Firefoxにしかアクセスできないので、サポートしたいブラウザー(おそらくIE、Chrome、Safari、Opera)で動作するかどうかをテストします。

0
Daan Wilmer

使用する良い動きがあります https://json5.org/ JSONで違法である多くのものが含まれているJSONの新しいスーパーセット

{
  // comments
  unquoted: 'and you can quote me on that',
  singleQuotes: 'I can use "double quotes" here',
  lineBreaks: "Look, Mom! \
No \\n's!",
  hexadecimal: 0xdecaf,
  leadingDecimalPoint: .8675309, andTrailing: 8675309.,
  positiveSign: +1,
  trailingComma: 'in objects', andIn: ['arrays',],
  "backwardsCompatible": "with JSON",
}

github: https://github.com/json5/json5

0
pery mimon