4

我想切换文件的扩展名。例如:

test_dir/test_file.jpg.txt应该给test_dir/test_file.txt

我还希望该解决方案可以处理具有两个扩展名的文件。

test_dir/test_file.ext1.jpg应该.txt应该给test_dir/test_file.ext1.txt

同样,在没有扩展名的文件上,它应该只添加扩展名。

test_dir/test_file应该给.txttest_dir/test_file.txt

我觉得这应该很简单,但我还没有找到一个简单的解决方案。这是我现在所拥有的。我认为它真的很难看,但它似乎确实有效。

def switch_ext(f, new_ext)
  File.join(File.dirname(f), File.basename(f, File.extname(f))) + new_ext
end

你有没有更优雅的方法来做到这一点?我在互联网上看过,但我猜我错过了一些明显的东西。有什么需要注意的问题吗?我更喜欢不使用正则表达式的解决方案。

4

8 回答 8

3

您的示例方法并不那么难看。请继续在字符串正则表达式上使用文件命名语义感知方法。您可以尝试Pathnamestdlib ,这可能会使它更干净一些:

require 'pathname'

def switch_ext(f, new_ext)
  p = Pathname.new f
  p.dirname + "#{ p.basename('.*') }#{ new_ext }"
end

>> puts %w{ test_dir/test_file.jpg test_dir/test_file.ext1.jpg testfile .vimrc }.
 | map{|f| switch_ext f, '.txt' }
test_dir/test_file.txt
test_dir/test_file.ext1.txt
testfile.txt
.vimrc.txt
于 2012-11-15T01:32:47.200 回答
1
def switch_ext(filename, new_ext)
  filename.chomp( File.extname(filename)) + new_ext
end

我刚刚在这个长期讨论的底部找到了我自己的问题的答案。 http://www.ruby-forum.com/topic/179524

我个人认为这是我见过的最好的一个。我绝对想避免使用正则表达式,因为它们对我来说很难记住,因此容易出错。

对于点文件,此函数只是将扩展名添加到文件中。这种行为对我来说似乎是明智的。

switch_ext('.vimrc', '.txt') # => ".vimrc.txt"

如果有任何问题,请继续发布更好的答案,并发表评论让我知道您是否在此答案中发现任何缺陷。我现在将问题悬而未决。

于 2012-11-15T09:11:48.100 回答
1
def switch_ext(f, new_ext)
  (n = f.rindex('.')) == 0 ?  nil : (f[0..n] + new_ext)
end

'.'如果它不是第一个字符,它将找到最正确的出现。

于 2012-11-15T01:42:06.350 回答
1

正则表达式是为这类任务发明的。

def switch_ext f, new_ext
  f.sub(/((?<!\A)\.[^.]+)?\Z/, new_ext)
end

puts switch_ext 'test_dir/test_file.jpg', '.txt'
puts switch_ext 'test_dir/test_file.ext1.jpg', '.txt'
puts switch_ext 'testfile', '.txt'
puts switch_ext '.vimrc', '.txt'

输出:

test_dir/test_file.txt
test_dir/test_file.ext1.txt
testfile.txt
.vimrc.txt
于 2012-11-15T00:32:03.607 回答
0
def switch_ext(filename, ext)
    begin
        filename[/\.\w+$/] = ext
    rescue
        filename << ext
    end
    filename
end

用法

>> switch_ext('test_dir/test_file.jpeg', '.txt')
=> "test_dir/test_file.txt"

>> switch_ext('test_dir/no_ext_file', '.txt')
=> "test_dir/no_ext_file.txt"

希望这有帮助。

于 2012-11-15T03:08:18.627 回答
0

您可以使用正则表达式,也可以使用内置文件名操作工具之类的东西File

%w[
  test_dir/test_file.jpg
  test_dir/test_file.ext1.jpg
  test_dir/test_file
].each do |fn|
  puts File.join(
    File.dirname(fn),
    File.basename(fn, File.extname(fn)) + '.txt'
  )
end

哪个输出:

test_dir/test_file.txt
test_dir/test_file.ext1.txt
test_dir/test_file.txt

我个人使用这些File方法。他们知道不同操作系统对文件名分隔符的需求,因此移植到另一个操作系统是轻而易举的事。在您的用例中,这没什么大不了的。混合路径操作,它变得更加重要。

于 2012-11-15T00:34:41.740 回答
0
def switch_ext f, new_ext
  "#{f.sub(/\.[^.]+\z/, "")}.#{new_ext}"
end
于 2012-11-15T03:12:01.850 回答
0

Since Ruby 1.9.1 the easiest answer is Pathname::sub_ext(replacement) which strips off the extension and replaces it with the given replacement (which can be an empty string ''):

Pathname.new('test_dir/test_file.jpg').sub_ext('.txt')
=> #<Pathname:test_dir/test_file.txt>

Pathname.new('test_dir/test_file.ext1.jpg').sub_ext('.txt')
=> #<Pathname:test_dir/test_file.ext1.txt>

Pathname.new('test_dir/test_file').sub_ext('.txt')
=> #<Pathname:test_dir/test_file.txt>

Pathname.new('test_dir/test_file.txt').sub_ext('')
=> #<Pathname:test_dir/test_file>

One thing to watch out for is that you need to have a leading . in the replacement:

Pathname.new('test_dir/test_file.jpg').sub_ext('txt')
=> #<Pathname:test_dir/test_filetxt>
于 2020-06-17T10:58:13.287 回答