{"id":1766,"date":"2021-03-11T12:55:11","date_gmt":"2021-03-11T17:55:11","guid":{"rendered":"http:\/\/www.jaimerios.com\/?p=1766"},"modified":"2025-12-02T23:35:57","modified_gmt":"2025-12-02T23:35:57","slug":"canonicalizing-a-url-path-using-stdfilesystemcanonical","status":"publish","type":"post","link":"https:\/\/jaimerios.com\/?p=1766","title":{"rendered":"Canonicalizing a URL path using std::filesystem::canonical"},"content":{"rendered":"\n<p>More specially, a file path where we are trying to remove  <code>..<\/code> and <code>.<\/code><\/p>\n\n\n\n<p>So, if you have &#8220;projects\/vectorization\/..\/gitstuff\/.\/..\/..\/something\/index.html&#8221; canonicalizing the string would reduce it to &#8220;something\/index.html&#8221;<\/p>\n\n\n\n<p>We have a couple of options to do this.<\/p>\n\n\n\n<p><strong>Option 1 &#8211; use std::filesystem<\/strong><br> Since C++17, you can take a path, and canonicalize it using <code>std::filesystem::canonical<\/code>.<\/p>\n\n\n\n<p>For paths that do not exist, or you just want to mess around, you can use <code>std::filesystem::weakly_canonical<\/code> to remove <code>..<\/code> and <code>.<\/code>.<\/p>\n\n\n\n<p>It\u2019s really simple to work with, and here\u2019s an example of how to use it:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 0 16px;font-size:0.8em;width:100%;text-align:left;background-color:#1E1E1E;font-style:italic;color:#D4D4D4\"><span style=\"border-bottom:1px solid rgba(234, 191, 191, 0.2)\">C++<\/span><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>void option_one(std::string&amp; path)\n{\n  auto fs_path   = fs::path(path);\n  auto canonical = fs::weakly_canonical(fs_path);\n  std::cout &lt;&lt; canonical &lt;&lt; '\\n';\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">void<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">option_one<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::<\/span><span style=\"color: #4EC9B0\">string<\/span><span style=\"color: #569CD6\">&amp;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">path<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">auto<\/span><span style=\"color: #D4D4D4\"> fs_path   = <\/span><span style=\"color: #4EC9B0\">fs<\/span><span style=\"color: #D4D4D4\">::<\/span><span style=\"color: #DCDCAA\">path<\/span><span style=\"color: #D4D4D4\">(path);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">auto<\/span><span style=\"color: #D4D4D4\"> canonical = <\/span><span style=\"color: #4EC9B0\">fs<\/span><span style=\"color: #D4D4D4\">::<\/span><span style=\"color: #DCDCAA\">weakly_canonical<\/span><span style=\"color: #D4D4D4\">(fs_path);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::cout &lt;&lt; canonical &lt;&lt; <\/span><span style=\"color: #CE9178\">&#39;<\/span><span style=\"color: #D7BA7D\">\\n<\/span><span style=\"color: #CE9178\">&#39;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><strong>Option 2 &#8211; use a stack<\/strong><br> We can use a stack to hold the path components, that we find while iterating up through a string.<\/p>\n\n\n\n<p>This will be a lot more involved than Option 1, but if C++17 is not available in your project, then:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 0 16px;font-size:0.8em;width:100%;text-align:left;background-color:#1E1E1E;font-style:italic;color:#D4D4D4\"><span style=\"border-bottom:1px solid rgba(234, 191, 191, 0.2)\">C++<\/span><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>\/**********************************************************\/\nstd::string option_two(std::string&amp; path)\n{\n  \/\/ Don't work on an empty path\n  if (path.empty())\n    return \"\";\n\n  \/\/ Use a stack to hold each path component\n  auto path_components = std::stack&lt;std::string>();\n\n  \/\/ Use 2 variables to hold the beginning and the end of a path component string\n  \/\/ initialized to the beginning of the string, and the first slash found\n  auto beginning = 0;\n  auto end = path.find(\"\/\", beginning);\n\n  \/\/ Now, walk up the string, gathering each path component\n  while (end != std::string::npos)\n  {\n    \/\/ Check if the path component is a `..` or `.`\n    const auto item = path.substr(beginning, end - beginning);\n\n    \/\/ If it's a `..`, pop the stack, otherwise ignore `.` and only add a path component\n    if (item == \"..\" &amp;&amp; !path_components.empty())\n      path_components.pop();\n    else if (item != \".\")\n      path_components.push(item);\n\n    \/\/ Set our variables to the current slash position, and the next found slash\n    beginning = end + 1;\n    end = path.find(\"\/\", beginning);\n  }\n\n  \/\/ Add the last path component, if we have a trailing one\n  if ((path.length() - beginning) > 0)\n  {\n    const auto last = path.substr(beginning, path.length() - beginning);\n    if (last != \"..\" &amp;&amp; last != \".\")\n      path_components.push(last);\n  }\n\n  \/\/ Reverse the stack to make our mechanism work\n  std::stack&lt;std::string> rpath_components;\n  while (!path_components.empty())\n  {\n    rpath_components.push(path_components.top());\n    path_components.pop();\n  }\n\n  \/\/ Append the path components to our string, delimited with `\/`\n  std::string canonical;\n  while (!rpath_components.empty())\n  {\n    canonical += rpath_components.top();\n    rpath_components.pop();\n    canonical += \"\/\";\n  }\n\n  \/\/ Remove the last trailing forward slash\n  canonical = canonical.substr(0, canonical.length() - 1);\n\n  std::cout &lt;&lt; canonical &lt;&lt; \"\\n\";\n  return canonical;\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #6A9955\">\/**********************************************************\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::<\/span><span style=\"color: #4EC9B0\">string<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">option_two<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::<\/span><span style=\"color: #4EC9B0\">string<\/span><span style=\"color: #569CD6\">&amp;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">path<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">  \/\/ Don&#39;t work on an empty path<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #9CDCFE\">path<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">empty<\/span><span style=\"color: #D4D4D4\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">  \/\/ Use a stack to hold each path component<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">auto<\/span><span style=\"color: #D4D4D4\"> path_components = <\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::<\/span><span style=\"color: #DCDCAA\">stack<\/span><span style=\"color: #D4D4D4\">&lt;<\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::<\/span><span style=\"color: #4EC9B0\">string<\/span><span style=\"color: #D4D4D4\">&gt;();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">  \/\/ Use 2 variables to hold the beginning and the end of a path component string<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">  \/\/ initialized to the beginning of the string, and the first slash found<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">auto<\/span><span style=\"color: #D4D4D4\"> beginning = <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">auto<\/span><span style=\"color: #D4D4D4\"> end = <\/span><span style=\"color: #9CDCFE\">path<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">find<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;\/&quot;<\/span><span style=\"color: #D4D4D4\">, beginning);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">  \/\/ Now, walk up the string, gathering each path component<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #C586C0\">while<\/span><span style=\"color: #D4D4D4\"> (end != <\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::<\/span><span style=\"color: #4EC9B0\">string<\/span><span style=\"color: #D4D4D4\">::npos)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">    \/\/ Check if the path component is a `..` or `.`<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">auto<\/span><span style=\"color: #D4D4D4\"> item = <\/span><span style=\"color: #9CDCFE\">path<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">substr<\/span><span style=\"color: #D4D4D4\">(beginning, end - beginning);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">    \/\/ If it&#39;s a `..`, pop the stack, otherwise ignore `.` and only add a path component<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (item == <\/span><span style=\"color: #CE9178\">&quot;..&quot;<\/span><span style=\"color: #D4D4D4\"> &amp;&amp; !<\/span><span style=\"color: #9CDCFE\">path_components<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">empty<\/span><span style=\"color: #D4D4D4\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #9CDCFE\">path_components<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">pop<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">else<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (item != <\/span><span style=\"color: #CE9178\">&quot;.&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #9CDCFE\">path_components<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">push<\/span><span style=\"color: #D4D4D4\">(item);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">    \/\/ Set our variables to the current slash position, and the next found slash<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    beginning = end + <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    end = <\/span><span style=\"color: #9CDCFE\">path<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">find<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;\/&quot;<\/span><span style=\"color: #D4D4D4\">, beginning);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">  \/\/ Add the last path component, if we have a trailing one<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> ((<\/span><span style=\"color: #9CDCFE\">path<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">length<\/span><span style=\"color: #D4D4D4\">() - beginning) &gt; <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">auto<\/span><span style=\"color: #D4D4D4\"> last = <\/span><span style=\"color: #9CDCFE\">path<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">substr<\/span><span style=\"color: #D4D4D4\">(beginning, <\/span><span style=\"color: #9CDCFE\">path<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">length<\/span><span style=\"color: #D4D4D4\">() - beginning);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (last != <\/span><span style=\"color: #CE9178\">&quot;..&quot;<\/span><span style=\"color: #D4D4D4\"> &amp;&amp; last != <\/span><span style=\"color: #CE9178\">&quot;.&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #9CDCFE\">path_components<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">push<\/span><span style=\"color: #D4D4D4\">(last);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">  \/\/ Reverse the stack to make our mechanism work<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::stack&lt;<\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::string&gt; rpath_components;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #C586C0\">while<\/span><span style=\"color: #D4D4D4\"> (!<\/span><span style=\"color: #9CDCFE\">path_components<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">empty<\/span><span style=\"color: #D4D4D4\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">rpath_components<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">push<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">path_components<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">top<\/span><span style=\"color: #D4D4D4\">());<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">path_components<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">pop<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">  \/\/ Append the path components to our string, delimited with `\/`<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::string canonical;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #C586C0\">while<\/span><span style=\"color: #D4D4D4\"> (!<\/span><span style=\"color: #9CDCFE\">rpath_components<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">empty<\/span><span style=\"color: #D4D4D4\">())<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    canonical += <\/span><span style=\"color: #9CDCFE\">rpath_components<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">top<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">rpath_components<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">pop<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    canonical += <\/span><span style=\"color: #CE9178\">&quot;\/&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\">  \/\/ Remove the last trailing forward slash<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  canonical = <\/span><span style=\"color: #9CDCFE\">canonical<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">substr<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">canonical<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">length<\/span><span style=\"color: #D4D4D4\">() - <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #4EC9B0\">std<\/span><span style=\"color: #D4D4D4\">::cout &lt;&lt; canonical &lt;&lt; <\/span><span style=\"color: #CE9178\">&quot;<\/span><span style=\"color: #D7BA7D\">\\n<\/span><span style=\"color: #CE9178\">&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> canonical;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>So, you can see there are 2 ways, and lots more if you put your mind to it, of canonicalizing a path.<\/p>\n\n\n\n<p>Happy coding!<\/p>\n\n\n\n<p>Refs<br><a href=\"https:\/\/en.cppreference.com\/w\/cpp\/filesystem\/canonical\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\" https:\/\/en.cppreference.com\/w\/cpp\/filesystem\/canonical (opens in a new tab)\"> https:\/\/en.cppreference.com\/w\/cpp\/filesystem\/canonical<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>More specially, a file path where we are trying to remove .. and . So, if you have &#8220;projects\/vectorization\/..\/gitstuff\/.\/..\/..\/something\/index.html&#8221; canonicalizing the string would reduce it to &#8220;something\/index.html&#8221; We have a couple of options to do this. Option 1 &#8211; use std::filesystem Since C++17, you can take a path, and canonicalize it using std::filesystem::canonical. For paths &#8230; <a title=\"Canonicalizing a URL path using std::filesystem::canonical\" class=\"read-more\" href=\"https:\/\/jaimerios.com\/?p=1766\" aria-label=\"Read more about Canonicalizing a URL path using std::filesystem::canonical\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[143],"class_list":["post-1766","post","type-post","status-publish","format-standard","hentry","category-coding","tag-cpp"],"_links":{"self":[{"href":"https:\/\/jaimerios.com\/index.php?rest_route=\/wp\/v2\/posts\/1766","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jaimerios.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jaimerios.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jaimerios.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jaimerios.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1766"}],"version-history":[{"count":1,"href":"https:\/\/jaimerios.com\/index.php?rest_route=\/wp\/v2\/posts\/1766\/revisions"}],"predecessor-version":[{"id":1891,"href":"https:\/\/jaimerios.com\/index.php?rest_route=\/wp\/v2\/posts\/1766\/revisions\/1891"}],"wp:attachment":[{"href":"https:\/\/jaimerios.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1766"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jaimerios.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1766"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jaimerios.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1766"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}