如何在 R 中使用 paste in for 循环?更改照片的 EXIF 数据
How to use paste in for loop in R? to change exif data of photos
我正在使用 R 版本 4.0.4 (2021-02-15) 的 MacOS Big Sur 11.6
我正在尝试在 for 循环中使用 paste(),但我需要 paste 函数中的值随着每次迭代而改变。
我有这样一个数据框:
pathname S
1 user/folder/photo1 A
2 user/folder/photo2 B
3 user/folder/photo3 C
我正在尝试将 EXIF Comment 标签添加到我照片的元数据中。我希望 Comment 标记根据 S 列值进行更改。我有这样的代码:
for(i in df$pathname){
x <- df$S[i]
sysCommand <- paste("exiftool -Comment=x i")
system(sysCommand)
}
粘贴函数中的输入(即 x 和 i)在遍历列表时应该发生变化。
感谢您的帮助!
你错在哪里
您对 paste()
的解释有误。此函数接受 R objects 并连接它们的字符串表示形式。
如此给出
name <- "Rogue"
然后是代码
paste("Hi name!", " How are you?")
将简单地连接字符串对象 "Hi name!"
和 " How are you?"
以产生
[1] "Hi name! How are you?"
要在 name
中进行替换,必须使用 name
对象
paste("Hi ", name, "!", " How are you?")
# ^^^^
获得
[1] "Hi Rogue! How are you?"
解决方法一:paste()
正确使用
正如评论所正确暗示的那样,paste()
的正确使用应该是
# ...
sysCommand <- paste("exiftool -Comment=", x, " ", i, sep = "")
# ^^^^^^^^
# Avoid unwanted spaces.
# ...
注意包含参数 sep = ""
,从而避免像 "exiftool -Comment= A 1"
中那样的额外空格。每个结果应如下所示:
[1] "exiftool -Comment=A 1"
备注
paste0()
函数会自动省略多余的空格,因此不需要 sep = ""
.
解决方案 2:glue
包
要使事情按您预期的方式工作,您可以使用 glue
程序包。
# ...
sysCommand <- glue::glue("exiftool -Comment={x} {i}")
# ...
注意用{ }
“拥抱”每个变量名。每个结果应该看起来像
exiftool -Comment=A 1
一个 glue
也是普通字符串的对象。
备注
正如我在
中提到的
You've extracted your data incorrectly with for(i in df$pathname)
and df$S[i]
. When you use i
in df$pathname
, you're iterating with i
over the strings "user/folder/photo1"
, "user/folder/photo2"
, and so forth. By contrast, df$S[i]
expects a number within the [ ]
, as it attempts to take the value in the i
th place of column S
. Since it can't interpret a string like "user/folder/photo1"
as a numeric
index, the operation df$S[i]
returns an NA
value...which paste()
interprets as the string "NA"
.
您的原始代码 在访问 df
中的数据时也 存在逻辑错误。漂亮的 by @dave2e 为这个错误提供了一个干净的向量化解决方案。
也就是说,您的 很好地解决了这个问题
for(i in 1:length(df$pathname)){
#for each photo
x <- df$S[i]
pathname <- df$pathname[i]
syscommand <- paste("exiftool -Comment=", site, " ", pathname, sep = "")
system(syscommand)
}
并且它保留了原始循环的结构。我很高兴听到它有效!
扩展@Greg 对粘贴功能的出色解释。与访问数据框中的数据相关的逻辑存在一些缺陷。
另外paste()
是一个向量化的函数,它更容易将系统命令制作一个向量然后只使用循环来执行命令。这避免了处理下标。
data<- read.table(header=TRUE, text=" pathname S
user/folder/photo1 A
user/folder/photo2 B
user/folder/photo3 C")
#paste is vectorized function
# create a list of all of the requested system commands
commands <-paste0("exiftool -Comment=", data$S, " ", data$pathname)
#loop through the vectors of command
for (i in commands) {
print(i) #debugging
system(i)
}
我正在使用 R 版本 4.0.4 (2021-02-15) 的 MacOS Big Sur 11.6
我正在尝试在 for 循环中使用 paste(),但我需要 paste 函数中的值随着每次迭代而改变。
我有这样一个数据框:
pathname S
1 user/folder/photo1 A
2 user/folder/photo2 B
3 user/folder/photo3 C
我正在尝试将 EXIF Comment 标签添加到我照片的元数据中。我希望 Comment 标记根据 S 列值进行更改。我有这样的代码:
for(i in df$pathname){
x <- df$S[i]
sysCommand <- paste("exiftool -Comment=x i")
system(sysCommand)
}
粘贴函数中的输入(即 x 和 i)在遍历列表时应该发生变化。
感谢您的帮助!
你错在哪里
您对 paste()
的解释有误。此函数接受 R objects 并连接它们的字符串表示形式。
如此给出
name <- "Rogue"
然后是代码
paste("Hi name!", " How are you?")
将简单地连接字符串对象 "Hi name!"
和 " How are you?"
以产生
[1] "Hi name! How are you?"
要在 name
中进行替换,必须使用 name
对象
paste("Hi ", name, "!", " How are you?")
# ^^^^
获得
[1] "Hi Rogue! How are you?"
解决方法一:paste()
正确使用
正如评论所正确暗示的那样,paste()
的正确使用应该是
# ...
sysCommand <- paste("exiftool -Comment=", x, " ", i, sep = "")
# ^^^^^^^^
# Avoid unwanted spaces.
# ...
注意包含参数 sep = ""
,从而避免像 "exiftool -Comment= A 1"
中那样的额外空格。每个结果应如下所示:
[1] "exiftool -Comment=A 1"
备注
paste0()
函数会自动省略多余的空格,因此不需要 sep = ""
.
解决方案 2:glue
包
要使事情按您预期的方式工作,您可以使用 glue
程序包。
# ...
sysCommand <- glue::glue("exiftool -Comment={x} {i}")
# ...
注意用{ }
“拥抱”每个变量名。每个结果应该看起来像
exiftool -Comment=A 1
一个 glue
也是普通字符串的对象。
备注
正如我在
You've extracted your data incorrectly with
for(i in df$pathname)
anddf$S[i]
. When you usei
indf$pathname
, you're iterating withi
over the strings"user/folder/photo1"
,"user/folder/photo2"
, and so forth. By contrast,df$S[i]
expects a number within the[ ]
, as it attempts to take the value in thei
th place of columnS
. Since it can't interpret a string like"user/folder/photo1"
as anumeric
index, the operationdf$S[i]
returns anNA
value...whichpaste()
interprets as the string"NA"
.
您的原始代码 在访问 df
中的数据时也 存在逻辑错误。漂亮的
也就是说,您的
for(i in 1:length(df$pathname)){
#for each photo
x <- df$S[i]
pathname <- df$pathname[i]
syscommand <- paste("exiftool -Comment=", site, " ", pathname, sep = "")
system(syscommand)
}
并且它保留了原始循环的结构。我很高兴听到它有效!
扩展@Greg 对粘贴功能的出色解释。与访问数据框中的数据相关的逻辑存在一些缺陷。
另外paste()
是一个向量化的函数,它更容易将系统命令制作一个向量然后只使用循环来执行命令。这避免了处理下标。
data<- read.table(header=TRUE, text=" pathname S
user/folder/photo1 A
user/folder/photo2 B
user/folder/photo3 C")
#paste is vectorized function
# create a list of all of the requested system commands
commands <-paste0("exiftool -Comment=", data$S, " ", data$pathname)
#loop through the vectors of command
for (i in commands) {
print(i) #debugging
system(i)
}