首页 > 解决方案 > URL 解析练习 (JavaScript)

问题描述

所以这里是对我一直在解决的问题的描述:

我们需要一些将 url 的可变部分提取到哈希中的逻辑。提取散列的键将是 url 可变部分的“名称”,散列的值将是值。我们将提供:

  1. 一个url格式字符串,描述了一个url的格式。url 格式字符串可以包含任意顺序的常量部分和可变部分,其中 url 的“部分”用“/”分隔。所有可变部分都以冒号开头。以下是此类 url 格式字符串的示例:
 '/:version/api/:collection/:id'
  1. 保证具有由 url 格式字符串给出的格式的特定url 实例。它还可能包含 url 参数。例如,给定上面的示例 url 格式字符串,url 实例可能是:
'/6/api/listings/3?sort=desc&limit=10'

鉴于此示例 url 格式字符串和 url 实例,我们想要将 url 实例的所有变量部分映射到它们的值的哈希将如下所示:

{
 version: 6,
 collection: 'listings',
 id: 3,
 sort: 'desc',
 limit: 10
}

所以我在技术上对此有一个半可行的解决方案,但是,我的问题是:

  1. 我是否正确理解了任务?我不确定我是否应该处理两个输入(URL 格式字符串和 URL 实例),或者我是否应该只处理一个 URL 作为一个整体。(我的解决方案需要两个单独的输入)

  2. 在我的解决方案中,我不断重复使用 split() 方法将数组分块,感觉有点重复。有一个更好的方法吗?

如果有人可以帮助我更好地理解这个挑战和/或帮助我清理我的解决方案,我们将不胜感激!

这是我的 JS:

const obj = {};

function parseUrl(str1, str2) {
  const keyArr = [];
  const valArr = [];
  const splitStr1 = str1.split("/");
  const splitStr2 = str2.split("?");
  let val1 = splitStr2[0].split("/");
  let val2 = splitStr2[1].split("&");

  splitStr1.forEach((i) => {
    keyArr.push(i);
  });
  val1.forEach((i) => {
    valArr.push(i);
  });

  val2.forEach((i) => {
    keyArr.push(i.split("=")[0]);
    valArr.push(i.split("=")[1]);
  });

  for (let i = 0; i < keyArr.length; i++) {
    if (keyArr[i] !== "" && valArr[i] !== "") {
      obj[keyArr[i]] = valArr[i];
    }
  }
  return obj;
};

console.log(parseUrl('/:version/api/:collection/:id', '/6/api/listings/3?sort=desc&limit=10'));

这是我的 codepen 的链接,因此您可以在控制台中看到我的输出: https ://codepen.io/TOOTCODER/pen/yLabpBo?editors=0012

标签: javascriptarraysobjectparsingurl

解决方案


我是否正确理解了任务?我不确定我是否应该处理两个输入(URL 格式字符串和 URL 实例),或者我是否应该将一个 URL 作为一个整体进行处理。(我的解决方案需要两个单独的输入)

是的,您对问题的理解对我来说似乎是正确的。这个任务似乎要求你做的是实现一个路由参数和一个查询字符串解析器。当您想从服务器端的部分 URL 中提取数据时,通常会出现这些问题(尽管您通常不需要自己实现此逻辑)。但是请记住,您只想获取路径参数,如果它们:前面有 a (当前您正在检索所有的所有值),而不是所有参数(例如:api在您的答案中应该从对象中排除(即:哈希))。

在我的解决方案中,我不断重复使用 split() 方法来分块数组,感觉有点重复。有一个更好的方法吗?

您拥有的方法的数量.split()可能看起来很多,但它们中的每一个都有其提取所需数据的目的。但是,您可以更改代码以使用其他数组方法(例如.map()等).filter()来稍微减少代码。下面的代码还考虑了没有提供查询字符串(即:)的情况?key=value

function parseQuery(queryString) {
  return queryString.split("&").map(qParam => qParam.split("="));
}
function parseUrl(str1, str2) {
  const keys = str1.split("/")
    .map((key, idx) => [key.replace(":", ""), idx, key.charAt(0) === ":"])
    .filter(([,,keep]) => keep);
  
  const [path, query = ""] = str2.split("?");
  const pathParts = path.split("/");
  const entries = keys.map(([key, idx]) => [key, pathParts[idx]]);
  
  return Object.fromEntries(query ? [...entries, ...parseQuery(query)] : entries);
}

console.log(parseUrl('/:version/api/:collection/:id', '/6/api/listings/3?sort=desc&limit=10'));

如果您不必重新发明轮子,而是使用URL 构造函数,那就更好了,这将允许您更轻松地从 URL 中提取所需的信息,例如搜索参数、this、但是,要求两个字符串都是有效的 URL

function parseUrl(str1, str2) {
  const {pathname, searchParams} = new URL(str2);
  const keys = new URL(str1).pathname.split("/")
    .map((key, idx) => [key.replace(":", ""), idx, key.startsWith(":")])
    .filter(([,,keep]) => keep);
   
   const pathParts = pathname.split("/");
   const entries = keys.map(([key, idx]) => [key, pathParts[idx]]);
   return Object.fromEntries([...entries, ...searchParams]);
}

console.log(parseUrl('https://www.example.com/:version/api/:collection/:id', 'https://www.example.com/6/api/listings/3?sort=desc&limit=10'));

上面,我们仍然需要编写自己的自定义逻辑来获取 URL 参数,但是,我们不需要编写任何逻辑来提取查询字符串数据,因为这是使用 URLSearchParams 为我们完成的。我们还能够减少.split()使用的 s 的数量,因为我们可以使用 URL 构造函数为我们提供一个已经解析 URL 的对象。如果您最终使用库(例如express),您将获得开箱即用的上述功能。


推荐阅读