亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

制作一個將 URL 字符串轉換為 JSON 的遞歸算法

制作一個將 URL 字符串轉換為 JSON 的遞歸算法

拉風的咖菲貓 2023-07-14 14:52:37
我發現自己必須處理如下字符串:foo=bar&foo1=foo%3Dbar%26foo2%3Dfoo%253Dbar進入:{? "foo": "bar",? "foo1": {? ? "foo": "bar",? ? "foo2": {? ? ? "foo": "bar"? ? }? }}我最好的嘗試是:function parse(input) {? try {? ? const parsed = JSON.parse(input);? ? return parseJSON(parsed);? } catch (err) {? ? const decodedInput = decodeURIComponent(input);? ? if (input.includes("&") && input.includes("=")) {? ? ? return input.split("&").reduce((json, part) => {? ? ? ? const [key, value] = part.split("=");? ? ? ? const decodedValue = decodeURIComponent(value);? ? ? ? return { ...json, [key]: parsePrimitive(decodedValue) };? ? ? }, {});? ? }? ? return decodedInput;? }}function parsePrimitive(input) {? if (!isNaN(input)) {? ? return Number(input);? }? if (input === "true" || input === "false") {? ? return input === "true";? }? return parse(input);}function parseJSON(input) {? return Object.entries(input).reduce((json, [key, value]) => {? ? let object = {};? ? if (typeof value === "object") {? ? ? if (Array.isArray(value)) {? ? ? ? object[key] = value;? ? ? } else {? ? ? ? object[key] = parseJSON(value);? ? ? }? ? } else {? ? ? const decodedValue = decodeURIComponent(value);? ? ? if (decodedValue.includes("&") && decodedValue.includes("=")) {? ? ? ? object[key] = parse(decodedValue);? ? ? } else {? ? ? ? object[key] = parsePrimitive(decodedValue);? ? ? }? ? }? ? return { ...json, ...object };? }, {});}如果您嘗試運行它,您應該調用parse(input)但是,對于某些輸入它確實會失敗如何針對此類問題制定完美的遞歸算法?
查看完整描述

3 回答

?
桃花長相依

TA貢獻1860條經驗 獲得超8個贊

這似乎適用于您的簡單示例和更復雜的示例(現已更新以處理數字和布爾值):

const parse = (query) =>

? query .startsWith ('{')

? ? ? JSON .parse (query)

? : query .includes ('&') || query .includes ('=')

? ? ? Object .fromEntries (

? ? ? ? query .split ('&')?

? ? ? ? ? .map (p => p .split ('='))

? ? ? ? ? .map (([k, v]) => [k, parse (decodeURIComponent (v))])

? ? ? )

? : query .includes (',')

? ? ? query .split (',') .filter (Boolean) .map (parse)

? : isFinite (query)

? ? ? Number (query)

? : query .toLowerCase () == "true" || query .toLowerCase () == "false"

? ? ? query .toLowerCase () == "true"

? : // else

? ? query



const q = 'foo=bar&foo1=foo%3Dbar%26foo2%3Dfoo%253Dbar'

console .log (parse(q))


console.log('fetching larger example...')


fetch ('https://gist.githubusercontent.com/avi12/cd1d6728445608d64475809a8ddccc9c/raw/030974baed3eaadb26d9378979b83b1d30a265a3/url-input-example.txt')

? .then (res => res .text ())

? .then (parse)

? .then (console .log)

.as-console-wrapper {max-height: 100% !important; top: 0}

有兩個部分值得關注。


首先,這對逗號做了一個假設:它們表示數組元素之間的分隔。而且,更進一步,它假設空字符串不是有意的,從而將


watermark=%2Chttps%3A%2F%2Fs.ytimg.com%2Fyts%2Fimg%2Fwatermark%2Fyoutube_watermark-vflHX6b6E.png

%2Chttps%3A%2F%2Fs.ytimg.com%2Fyts%2Fimg%2Fwatermark%2Fyoutube_hd_watermark-vflAzLcD6.png

進入這個:


watermark: [

? "https://s.ytimg.com/yts/img/watermark/youtube_watermark-vflHX6b6E.png",

? "https://s.ytimg.com/yts/img/watermark/youtube_hd_watermark-vflAzLcD6.png"

]

原始內容以編碼的逗號 ( %2C) 開頭,這會導致初始空字符串,因此我們使用.filter (Boolean)刪除它。


其次,對表示 JSON 的字符串的測試非常幼稚,僅執行.startsWith ('{'). 您可以將其替換為您需要的任何內容,但這會導致意圖問題。我不確定我們是否可以以這種方式完全通用地編寫此內容。


不過,我認為已經很接近了。而且代碼相當干凈。


然而,我確實想知道為什么。這么多數據將會遇到各種 url 大小限制。此時,將其放入請求正文而不是 url 參數不是更有意義嗎?


查看完整回答
反對 回復 2023-07-14
?
POPMUISE

TA貢獻1765條經驗 獲得超5個贊

您可以通過檢查編碼符號來采用遞歸方法=。


const getValues = string => string.split('&')

    .reduce((r, pair) => {

      let [key, value] = pair.split('=');

      value = decodeURIComponent(value);

      r[key] = value.includes('=')

        ? getValues(value)

        : value;

      return r;

    }, {});


console.log(getValues('foo=bar&foo1=foo%3Dbar%26foo2%3Dfoo%253Dbar'));


查看完整回答
反對 回復 2023-07-14
?
呼啦一陣風

TA貢獻1802條經驗 獲得超6個贊

我使用Object.fromEntries?(new?URLSearchParams?())重新設計了算法。

function parse(query) {

? try {

? ? return JSON.parse(query);

? } catch {

? ? if (!isNaN(query)) {

? ? ? return Number(query);

? ? }


? ? if (typeof query !== "string") {

? ? ? const obj = {};

? ? ? for (const queryKey in query) {

? ? ? ? if (query.hasOwnProperty(queryKey)) {

? ? ? ? ? obj[queryKey] = parse(query[queryKey]);

? ? ? ? }

? ? ? }


? ? ? return obj;

? ? }

? ? if (!query) {

? ? ? return "";

? ? }


? ? if (query.toLowerCase().match(/^(true|false)$/)) {

? ? ? return query.toLowerCase() === "true";

? ? }


? ? const object = Object.fromEntries(new URLSearchParams(query));

? ? const values = Object.values(object);

? ? if (values.length === 1 && values[0] === "") {

? ? ? return query;

? ? }

? ? return parse(object);

? }

}




const q = 'foo=bar&foo1=foo%3Dbar%26foo2%3Dfoo%253Dbar';

console.log(parse(q));


console.log('fetching larger example...');


fetch('https://gist.githubusercontent.com/avi12/cd1d6728445608d64475809a8ddccc9c/raw/030974baed3eaadb26d9378979b83b1d30a265a3/url-input-example.txt')

? .then(response => response.text())

? .then(parse)

? .then(console.log);

.as-console-wrapper { max-height: 100% !important; top: 0; }



查看完整回答
反對 回復 2023-07-14
?
莫回無

TA貢獻1865條經驗 獲得超7個贊

Node.js 附帶了一個內置的“querystring”npm 包實用程序,但在這里我使用了一個更好的實用程序,稱為“qs”。您可以在數組中指定分隔符,而不是僅對前者使用一個分隔符。


如果您想使用內置的“querystring”包,則需要在調用解析時刪除分隔符數組,并檢查字符串以查看使用的分隔符 - 您提供的示例文件使用了幾個不同的分隔符。


所以試試這個:


const qs = require("qs");

let params = `foo=bar&foo1=foo%3Dbar%26foo2%3Dfoo%253Dbar`;


const isObject = (param) => {

  try {

    let testProp = JSON.parse(param);

    if (typeof testProp === "object" && testProp !== null) {

      return true;

    }

    return false;

  } catch (e) {

    return false;

  }

};


const isURL = (value) => {

  try {

    new URL(value);

  } catch (e) {

    return false;

  }

  return true;

};


const isQueryString = (value) => {

  if (/[/&=]/.test(value) && !isURL(value)) {

    return true;

  } else {

    return false;

  }

};


const parseData = (data, parsed = false) => {

  if (isQueryString(data) && !parsed) {

    return parseData(qs.parse(data, { delimiter: /[;,/&]/ }), true);

  } else if (isObject(data) || parsed) {

    for (let propertyName in data) {

      if (isObject(data[propertyName])) {

        data[propertyName] = parseData(JSON.parse(data[propertyName]), true);

      } else {

        data[propertyName] = parseData(data[propertyName]);

      }

    }


    return data;

  } else {

    return data;

  }

};

let s = parseData(params);

console.log(JSON.stringify(s, null, 2));


查看完整回答
反對 回復 2023-07-14
  • 3 回答
  • 0 關注
  • 194 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號