搜尋

首頁  >  問答  >  主體

建立一個正規表示式,將JSON值中沒有雙引號的部分加上雙引號

<p>我有很多格式錯誤的JSON字串,像這樣:</p> <pre class="brush:php;toolbar:false;">{ "id":23424938, "name":aN, "ref":aN, "jul":aN, "cat":{}, "src":[], "Code":"SA", "type":d, "spec":[i,j], "child":a }</pre> <p>我正在嘗試建立一個正規表示式來雙引號JSON值,但沒有成功。 </p> <p>我最終使用了<code>/":([^"d{[] ?[^,}]?)/</code>,它修復了所有問題,除了數組內的值,例如<code>[i,j]</code>,它不會轉換成<code>["i","j"]</code>。 </p> <p>你能幫我處理括號內的數值嗎? </p> <p>https://regex101.com/r/CGskmy/1</p>
P粉231112437P粉231112437466 天前515

全部回覆(1)我來回復

  • P粉755863750

    P粉7558637502023-08-18 11:23:05

    這個任務會有一些困難,因為有歧義。例如,{ "x": [y] } 是變成{ "x": "[y]" } 還是變成{ "x": [" y"] }?我會假設未加引號的字串不包含JSON 控製字符,例如'[', ']', '{', '}', '"', ':', ','

    我認為你可以使用命名捕獲組來完成這個任務,這是 PHP 中的一個功能,使用 PCRE 可以實現。這需要一些程式設計來執行替換。通常的 preg_replace 操作是不夠的,因為我們不會替換所有匹配項。

    這是我想出來的方法。首先,我匹配引號字串並忽略它們。其次,我匹配數字並忽略它們。最後,我匹配未加引號的字串並將其儲存在名為“unquoted”的捕獲組中。請注意,PCRE 將按照這些替代項的順序嘗試匹配。只有在無法匹配引號字串和數字時,才會匹配未加引號的字串。這是這種方法的關鍵。

    一旦我匹配到所有未加引號的字串,就只需要將輸出字串與替換一起拼接起來。這是透過迭代匹配項並將字串片段複製到輸出中來完成的。

    <?php
    
    $in = <<<'IN'
    {
        "id":23424938,
        "name":aN,
        "ref":aN,
        "jul":aN,
        "cat":{},
        "src":[],
        "Code":"SA",
        "type":d,
        "spec":[i,j],
        "child":a
    }
    IN;
    
    // 在输入字符串上匹配。我们特别关注“unquoted”匹配组。
    $pattern = '/(?:"(?:\\"|[^"])+")|(?:[\d.]+)|(?P<unquoted>[^{}\[\]":,\s][^{}\[\]":,]*(?<!\s))/';
    preg_match_all($pattern, $in, $matches, PREG_UNMATCHED_AS_NULL | PREG_OFFSET_CAPTURE);
    
    // 输出字符串
    $out = '';
    
    // 跟踪输入字符串的当前索引
    $ix = 0;
    
    // 循环遍历所有未加引号的匹配项
    foreach ($matches['unquoted'] as $match) {
        $str = $match[0];
        $pos = $match[1];
        if ($str !== NULL) {
            // 将输入字符串复制到输出字符串
            $out .= substr($in, $ix, $pos - $ix);
            // 将匹配的字符串复制到输出字符串,用引号括起来
            $out .= '"' . $str . '"';
            // 更新输入字符串索引
            $ix = $pos + strlen($str);
        }
    }
    
    // 将输入字符串的尾部复制到输出字符串
    $out .= substr($in, $ix, strlen($in) - $ix);
    
    // 输出字符串
    echo $out;
    

    我沒有處理完整的 JSON 數字語法,也沒有處理 JSON 語法,例如 truefalsenull。希望這個答案是一個起點,你可以根據自己的需求來調整。

    InSync 提供了一個很好的正規表示式,它不使用命名捕獲組,而是命令 PCRE 跳過不需要的匹配項。

    (?:
      "(?:[^\"rrreee-\x1F\x7F]|\["\/bfnrt]|\u[\dA-Fa-f]{4})*"
    |
      -?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?
    )
    (*SKIP)(*FAIL)
    |
    [^{}[\]:,\s]+

    回覆
    0
  • 取消回覆