我尝试使用Ruby更改文本文件中每个其他行的内容(以及一些文本文件,我需要每隔三行更改一些内容,依此类推。)
我发现this question有助于迭代每一行,但我特别需要帮助每x行更改一次。
###
是我遇到问题的部分(迭代x行数。)
text = File.open('fr.txt').read
clean = ### .sub("\n", " ");
new = File.new("edit_fr.txt", "w")
new.puts clean
new.close
答案 0 :(得分:4)
您可以使用下面的模数除法,其中n
指的是您要处理的第n行,i
指的是文件行的从0开始的索引。使用这两个值,模数学提供整数除法的余数,只要基于1的索引(i+1
)是n
的倍数,它就为0。
n = 3 # modify every 3rd line
File.open('edit_fr.txt','w') do |f| # Open the output file
File.open('fr.txt').each_with_index do |line,i| # Open the input file
if (i+1) % n == 0 # Every nth line
f.print line.chomp # Remove newline
else # Every non-nth line
f.puts line # Print line
end
end
end
维基百科上提供了更多信息:http://en.wikipedia.org/wiki/Modulo_operation
在计算中,模运算在一个数除以另一个数之后找到余数(有时称为模数)。
给定两个正数,a(被除数)和n(除数),模n(缩写为mod n)是a乘以欧几里得分的余数。例如,表达式" 5 mod 2"将评估为1,因为5除以2得到2的商和1的余数,而" 9 mod 3"将评估为0,因为9乘3的除数为3,余数为0;在乘以3次3后,没有什么要从9中减去。(注意,用计算器进行除法不会显示此操作引用的结果;商将表示为小数。)
答案 1 :(得分:1)
您希望将输入文件的每一行写入输出文件,但是您希望在写入之前修改输入文件的每个nth
行,从文件的第一行开始。
假设我们定义了一个方法modify
,它接受一行文本作为参数并返回一个修改过的字符串。然后你就可以这样做:
def modify_and_write(in_fname, out_fname, n)
enum = Array.new(n) { |i| i.zero? ? :process : :skip }.cycle
f = File.open(out_fname, 'w')
IO.foreach(in_fname) do |line|
(line = process(line)) if enum.next == :process
f.puts(line)
end
f.close
end
我一次只读一行(而不是使用IO#readlines)将整个文件读入数组中,以便它可以处理任何大小的文件。
假设:
n = 3
这里的关键是枚举器:
enum = Array.new(n) { |i| i.zero? ? :process : :skip }.cycle
#=> #<Enumerator: [:process, :skip, :skip]:cycle>
enum.next #=> :process
enum.next #=> :skip
enum.next #=> :skip
enum.next #=> :process
enum.next #=> :skip
enum.next #=> :skip
enum.next #=> :process
enum.next #=> :skip
...
编辑:在回答之后我注意到了OP的评论:I need to combine every two lines: line1 /n line2 /n line3 /n line would become line1 space line2 /n line3 space line4
,这与&#34不一致;我试图改变每个人的内容文本文件中的其他行&#34;。为了满足特定要求,我的解决方案可以修改如下:
def combine_lines(in_fname, out_fname, n)
enum = Array.new(n) { |i| (i==n-1) ? :write : :read }.cycle
f = File.open(out_fname, 'w')
combined = []
IO.foreach(in_fname) do |line|
combined << line.chomp
if enum.next == :write
f.puts(combined.join(' '))
combined.clear
end
end
f.puts(combined.join(' ')) if combined.any?
f.close
end
让我们试一试:
text =<<_
Now is
the time
for all
good
Rubyists
to do
something
other
than
code.
_
File.write('in',text)
combine_lines('in', 'out', 3)
puts File.read('out')
# Now is the time for all
# good Rubyists to do
# something other than
# code.
你也可以使用正则表达式,正如@Stefan所做的那样,这将是我对低于文件的偏好。这是另一个正则表达式实现:
def combine_lines(in_fname, out_fname, n)
IO.write(out_fname,
IO.read(in_fname)
.scan(/(?:.*?\n){1,#{n}}/)
.map { |s| s.split.join(' ') }
)
end
combine_lines('in', 'out', 3)
puts File.read('out')
# Now is the time for all
# good Rubyists to do
# something other than
# code.
我们可以编写上述正则表达式,并将最终/
更改为/x
以包含注释:
r = /
(?: # begin a non-capture group
.*? # match any number of any character, non-greedily
\n # match (the first, because of non-greedily) end-of-line
) # end the non-capture group
{1,#{n}} # match between 1 and n of the preceding non-capture group
/x
{1,#{n}}
&#34;贪婪&#34;从某种意义上说,它将匹配尽可能多的行,直到n
。如果行数始终是n
的倍数,我们可以改写{{#n}}
,即匹配n
非捕获组(即n
行)。但是,如果行数不是n
的倍数(如上例所示),我们需要{1,#{n}}
来匹配最后一个非捕获组中的最后几行。
答案 2 :(得分:0)
every_other = 2
File.open('data.txt') do |f|
e = f.each
target_line = nil
loop do
every_other.times do
target_line = e.next
end
puts target_line
end
end
答案 3 :(得分:0)
我认为你只需要一个正则表达式就可以做到:
修改强>
好的,我知道我可以使用each_slice
和一个简单的正则表达式来执行此操作:
def chop_it(file,num)
#file name and the number of lines to join
arr = []
#create an empty array to hold the lines we create
File.open(file) do |f|
#open your file into a `do..end` block, it closes automatically for you
f.each_slice(num) do |slice|
#get an array of lines equal to num
arr << slice.join(' ').gsub!(/\n/, '') + "\n"
#join the lines with ' ', then remove all the newlines and tack one
# on the end, adding the resulting line to the array.
end
end
arr.join
#join all of the lines back into one string that can be sent to a file.
end
你有它,简单而灵活。只需输入文件名和您想要减少到一行的行数。即如果你想加入每两行,chop_it('data.txt',2)
。每三个? chop_it('data.txt,3)
。
**旧答案**
old_text = File.read(data.txt)
new_text = old_text.gsub(/(?:(^.*)\n(^.*\n))/i,'\1 \2')
正则表达式将第一行与“\ n”匹配,第二行与“\ n”相匹配。替换返回两个匹配,它们之间有空格。
"this is line one\nthis is line two\n this is line three\nthis is line four]n"
\1 = "this is line one"
\2 = "this is line two\n"
'\1 \2' = "this is line one this is line two\n"
此正则表达式还将处理连续空白行中的每隔一个空白行
答案 4 :(得分:0)
new = File.new("edit_fr.txt", "w")
File.readlines("test.txt").each_slice(2) do |batch| # or each_slice(3) etc
new.puts batch.map(&:chomp).join(" ")
end
new.close
答案 5 :(得分:0)
我需要组合每两行:line1 / n line2 / n line3 / n line将成为line1 space line2 / n line3 space line4
您可以将read
整个文件转换为字符串,使用gsub!
和with_index
将每个 n 换行符替换为空格write
将替换的内容添加到新文件中:
content = IO.read('fr.txt')
content.gsub!("\n").with_index(1) { |m, i| (i % 2).zero? ? m : ' ' }
IO.write('edit-fr.txt', content)
输入fr.txt
:
line1
line2
line3
line4
输出edit-fr.txt
:
line1 line2
line3 line4