-- Converts tabs to spaces
function detab(text)
local tab_width = 4
local function rep(match)
local spaces = -match:len()
print("match:"..match)
while spaces<1 do spaces = spaces + tab_width end
print("Found "..spaces.." spaces")
return match .. string.rep(" ", spaces)
end
text = text:gsub("([^\n]-)\t", rep)
return text
end
str=' thisisa string'
--thiis is a string
print("length: "..str:len())
print(detab(str))
print(str:gsub("\t"," "))
我有来自markdown.lua的这段代码,它将标签转换为空格(顾名思义)。我设法弄清楚它是从头开始搜索的
字符串,直到找到一个制表符并将匹配的子字符串传递给'rep'
函数。它会反复执行,直到没有更多匹配为止
我的问题是试图找出rep函数正在做什么,特别是在
while循环。
为什么循环停在1
?
为什么它会计数?。
令人惊讶的是,它计算了弦乐中的空格数量,究竟是多么神秘
如果将其输出与上一个gsub
替换的输出进行比较,您会发现它们不同。
Detab维持
gsub
替换时没有对齐字符。 为什么会这样?
加分问题。当我在Scite中打开空白时,我可以看到't'
之前的标签比第三个's'
之前的标签长。 为什么他们不同?
答案 0 :(得分:4)
通过分析rep
函数,这就是它似乎正在做的事情。首先,它接受传入的匹配字符串的长度并使其为负(例如,将其乘以-1)。在while循环中,它会不断增加空间直到它变为正数。
使用数字行可能更容易将其可视化:
<--|----|-------|----|----|----|----|----|----|----|----|--->
-n -spaces -2 -1 0 1 2 n
本质上,循环试图计算在“溢出”之前有多少“tab_widths”可以适应空格。这里使用从0到1的转换作为截止点。在循环之后,spaces
将会溢出多少。
实际上,while循环模仿了一个你可能知道为模数的数学运算。换句话说,内部rep
函数可以重写为:
local function rep(match)
local spaces = tab_width - match:len() % tab_width
return match .. string.rep(" ", spaces)
end
这与外部str:gsub("\t", " ")
不同,其中不加选择地用4个空格替换所有制表符。 OTOH,在detab
函数中,替换制表符的空格数取决于匹配捕获的长度。
eg.
matching length is 1, replace tab with 3 spaces
matching length is 2, replace tab with 2 spaces
matching length is 3, replace tab with 1 space
matching length is n, replace tab with tab_width - (n % tab_width) spaces
etc.
答案 1 :(得分:1)
回答红利问题: 制表符对齐tabstops。一个tabstop是八个字符。第一个标签从第六列开始,因此需要填充三个空格。第二个选项卡从第16列开始,因此它只需要一个空格宽。
当空格变为正数时,循环停止,因为循环一直以“缩进”增量添加空格,直到它有足够的空格比匹配的文本更长。然后,当它将该数量的空格与匹配的文本组合时,它构造了一个填充到正确的tabstop的字符串。
这也是gsub不同的原因。 gsub不将制表符视为tabstop字符,而是将其视为四个空格。所以第二个标签不会填充到tabstop,而是扩展到四个空格。