Function to concatenate paths?
Yes, file.path()
R> file.path("usr", "local", "lib")
[1] "usr/local/lib"
R>
There is also the equally useful system.path()
for files in a package:
R> system.file("extdata", "date_time_zonespec.csv", package="RcppBDT")
[1] "/usr/local/lib/R/site-library/RcppBDT/extdata/date_time_zonespec.csv"
R>
which will get the file extdata/date_time_zonespec.csv
irrespective of
- where the package is installed, and
- the OS
which is very handy. Lastly, there is also
R> .Platform$file.sep
[1] "/"
R>
if you insist on doing it manually.
Concatenate path and file
You're using the wrong syntax for calling functions. In Powershell you separate arguments by a space and you also don't need to use ()
.
,
is the array-operator, so "C:\_Store", "run.sql"
actually passes an array of two strings to $Path
and because you're using the variable (containing an array) in a string, the strings are joined together with a whitespace. $File
is empty, which is why it ends with nothing after \
.
Try:
fnConcatenatePathFile "C:\_Store" "run.sql"
or to make it clearer:
fnConcatenatePathFile -Path "C:\_Store" -File "run.sql"
Concatenate path and filename
Backslash character (\
) has to be escaped in string literals.
- This is wrong:
'\'
- This is correct:
'\\'
- this is a string containing one backslash
Therefore, this is wrong:
'C:\Program Files (x86)\LibreOffice 5\program\soffice.exe'
There is a trick!
String literals prefixed by r
are meant for easier writing of regular expressions. One of their features is that backslash characters do not have to be escaped. So, this would be OK:
r'C:\Program Files (x86)\LibreOffice 5\program\soffice.exe'
However, that wont work for a string ending in backslash:
r'\'
- this is a syntax error
So, this is also wrong:
r'C:\Users\A\Desktop\Repo\'
So, I would do the following:
import os
import subprocess
soffice = 'C:\\Program Files (x86)\\LibreOffice 5\\program\\soffice.exe'
outdir = 'C:\\Users\\A\\Desktop\\Repo\\'
full_path = os.path.join(outdir, filename)
subprocess.call([soffice,
'--headless',
'--convert-to', 'pdf',
'--outdir', outdir,
full_path])
Platform independent path concatenation using / , \ ?
You want to use os.path.join() for this.
The strength of using this rather than string concatenation etc is that it is aware of the various OS specific issues, such as path separators. Examples:
import os
Under Windows 7:
base_dir = r'c:\bla\bing'
filename = r'data.txt'
os.path.join(base_dir, filename)
'c:\\bla\\bing\\data.txt'
Under Linux:
base_dir = '/bla/bing'
filename = 'data.txt'
os.path.join(base_dir, filename)
'/bla/bing/data.txt'
The os module contains many useful methods for directory, path manipulation and finding out OS specific information, such as the separator used in paths via os.sep
PHP concatenation of paths
I ran into this problem myself, primarily regarding the normalization of paths.
Normalization is:
- One separator (I've chosen to support, but never return a backwards slash
\\
) - Resolving indirection:
/../
- Removing duplicate separators:
/home/www/uploads//file.ext
- Always remove trailing separator.
I've written a function that achieves this. I don't have access to that code right now, but it's also not that hard to write it yourself.
Whether a path is absolute or not doesn't really matter for the implementation of this normalization function, just watch out for the leading separator and you're good.
I'm not too worried about OS dependence. Both Windows and Linux PHP understand /
so for the sake of simplicity I'm just always using that - but I guess it doesn't really matter what separator you use.
To answer your question: path concatenation can be very easy if you just always use /
and assume that a directory has no trailing separator. 'no trailing separator' seems like a good assumption because functions like dirname
remove the trailing separator.
Then it's always safe to do: $dir . "/" . $file
.
And even if the result path is /home/uploads/../uploads//my_uploads/myfile.ext
it's still going to work fine.
Normalization becomes useful when you need to store the path somewhere. And because you have this normalization function you can make these assumptions.
An additional useful function is a function to make relative paths.
- /files/uploads
- /files/uploads/my_uploads/myfile.ext
It can be useful to derive from those two paths, what the relative path to the file is.
realpath
I've found realpath
to be extremely performance heavy. It's not so bad if you're calling it once but if you're doing it in a loop somewhere you get a pretty big hit. Keep in mind that each realpath
call is a call to the filesystem as well. Also, it will simply return false
if you pass in something silly, I'd rather have it throw an Exception.
To me the realpath
function is a good example of a BAD function because it does two things: 1. It normalizes the path and 2. it checks if the path exists. Both of these functions are useful of course but they must be separated. It also doesn't distinguish between files and directories. For windows this typically isn't a problem, but for Linux it can be.
And I think there is some quirky-ness when using realpath("")
on Windows. I think it will return \\
- which can be profoundly unacceptable.
/**
* This function is a proper replacement for realpath
* It will _only_ normalize the path and resolve indirections (.. and .)
* Normalization includes:
* - directiory separator is always /
* - there is never a trailing directory separator
* @param $path
* @return String
*/
function normalize_path($path) {
$parts = preg_split(":[\\\/]:", $path); // split on known directory separators
// resolve relative paths
for ($i = 0; $i < count($parts); $i +=1) {
if ($parts[$i] === "..") { // resolve ..
if ($i === 0) {
throw new Exception("Cannot resolve path, path seems invalid: `" . $path . "`");
}
unset($parts[$i - 1]);
unset($parts[$i]);
$parts = array_values($parts);
$i -= 2;
} else if ($parts[$i] === ".") { // resolve .
unset($parts[$i]);
$parts = array_values($parts);
$i -= 1;
}
if ($i > 0 && $parts[$i] === "") { // remove empty parts
unset($parts[$i]);
$parts = array_values($parts);
}
}
return implode("/", $parts);
}
/**
* Removes base path from longer path. The resulting path will never contain a leading directory separator
* Base path must occur in longer path
* Paths will be normalized
* @throws Exception
* @param $base_path
* @param $longer_path
* @return string normalized relative path
*/
function make_relative_path($base_path, $longer_path) {
$base_path = normalize_path($base_path);
$longer_path = normalize_path($longer_path);
if (0 !== strpos($longer_path, $base_path)) {
throw new Exception("Can not make relative path, base path does not occur at 0 in longer path: `" . $base_path . "`, `" . $longer_path . "`");
}
return substr($longer_path, strlen($base_path) + 1);
}
What is a macro for concatenating an arbitrary number of components to build a path in Rust?
Once you read past the macro syntax, it's not too bad. Basically, we take require at least two arguments, and the first one needs to be convertible to a PathBuf
via Into
. Each subsequent argument is push
ed on the end, which accepts anything that can be turned into a reference to a Path
.
macro_rules! build_from_paths {
($base:expr, $($segment:expr),+) => {{
let mut base: ::std::path::PathBuf = $base.into();
$(
base.push($segment);
)*
base
}}
}
fn main() {
use std::{
ffi::OsStr,
path::{Path, PathBuf},
};
let a = build_from_paths!("a", "b", "c");
println!("{:?}", a);
let b = build_from_paths!(PathBuf::from("z"), OsStr::new("x"), Path::new("y"));
println!("{:?}", b);
}
Related Topics
Change the Position of the Strip Label in Ggplot from the Top to the Bottom
Why Has Data.Table Defined := Rather Than Overloading <-
Read Gzipped CSV Directly from a Url in R
Error: Vector Memory Exhausted (Limit Reached) R 3.5.0 MACos
Format Numbers to Significant Figures Nicely in R
Raw Text Strings for File Paths in R
Removing Specific Rows from a Dataframe
Export Data Frames to Excel via Xlsx with Conditional Formatting
R Command Line Passing a Filename to Script in Arguments (Windows)
Ggplot: Boxplot of Multiple Column Values
Check If a Date Is Within an Interval in R
R Tm Package Vcorpus: Error in Converting Corpus to Data Frame