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 語法,例如 true
、false
或 null
。希望這個答案是一個起點,你可以根據自己的需求來調整。
InSync 提供了一個很好的正規表示式,它不使用命名捕獲組,而是命令 PCRE 跳過不需要的匹配項。
(?: "(?:[^\"rrreee-\x1F\x7F]|\["\/bfnrt]|\u[\dA-Fa-f]{4})*" | -?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)? ) (*SKIP)(*FAIL) | [^{}[\]:,\s]+