如何正确解析统一差异中的范围信息?
How do I properly parse the range information in a unified diff?
基本上,我想做的就是看一个统一的diff的范围信息,然后确切地知道我应该关注哪些代码行。
例如,这个:
@@ -1827,7 +1827,7 @@
这告诉我总共只有 1 行发生了变化,因为差异显示了变化上下 3 行(所以 7 - 6 = 1),它还指向 1830 行(即 1827 + 3).
更迂腐地说,这个特定的范围信息实际上告诉我,在第 1830 行,删除了一行 (-),并在第 1830 行添加了一行 (+)。
或者为了更明显地考虑另一个差异的范围信息:
@@ -878,15 +878,13 @@
这告诉我的是,在第 881 行 (878 + 3) 删除了 9 行 (15 - 6),但在第 881 行仅添加了 7 行 (13 - 6)。
所以问题是,使用正则表达式或其他一些 Ruby 字符串方法,如何轻松提取上述信息?
即我如何轻松提取此信息:
两个 行号(即只是 1827 或 878),然后我可以加上 + 3 以确定我关心的实际内联号。 它必须是两者,因为两条线可能并不总是相同的。
- 受影响的行数(也就是上面示例中
,
之后的 7
、15
或 13
)
- 当我这样做时,我如何确保跟踪每个操作的操作(添加或删除)。
我尝试对字符串进行切片并直接找到一个字符——例如myString[3]
这给了我 -
,但这是它唯一可靠工作的字符,因为行号可以是 1、10、100、1000、10000 等。所以唯一的方法就是扫描字符串然后解析它。
编辑 1
添加一些代码来展示我的尝试。
假设我在名为 @diff_lines
:
的变量中有差异的内容
@diff_lines.each do |diff_line|
if diff_line.start_with?("@@")
del_line_num_start = diff_line.split(/@@ /).second.split.first.split(/-/).second.split(/,/).first.to_i + 3
num_deleted_lines = diff_line.split(/@@ /).second.split.first.split(/-/).second.split(/,/).second.to_i - 6
add_line_num_start = diff_line.split(/@@ /).second.split.second.split(/\+/).second.split(/,/).first.to_i + 3
num_added_lines = diff_line.split(/@@ /).second.split.second.split(/\+/).second.split(/,/).second.to_i - 6
如您所见,上面的方法有效....但看起来很可怕,而且显然不是很干。
理想情况下,我希望能够实现同样的事情,但更干净。
总体思路是编写一个包含捕获组 ((...)
) 的正则表达式,以将该字符串分解为有用的内容。例如:
diff_line.match(/\A@@\s+\-(\d+),(\d+)\s+\+(\d+),(\d+)\s+@@/)
这会在成功匹配时产生一个 MatchData 对象。然后,您可以将其应用于某些变量,例如:
if (m = diff_line.match(...))
a_start, a_len, b_start, b_len = m[1..4].map(&:to_i)
end
然后你可以用这些数字做任何你需要做的计算。
如果您在想象正则表达式的作用时遇到困难,请尝试使用像 Rubular 这样的工具来更好地说明内部结构。
基本上,我想做的就是看一个统一的diff的范围信息,然后确切地知道我应该关注哪些代码行。
例如,这个:
@@ -1827,7 +1827,7 @@
这告诉我总共只有 1 行发生了变化,因为差异显示了变化上下 3 行(所以 7 - 6 = 1),它还指向 1830 行(即 1827 + 3).
更迂腐地说,这个特定的范围信息实际上告诉我,在第 1830 行,删除了一行 (-),并在第 1830 行添加了一行 (+)。
或者为了更明显地考虑另一个差异的范围信息:
@@ -878,15 +878,13 @@
这告诉我的是,在第 881 行 (878 + 3) 删除了 9 行 (15 - 6),但在第 881 行仅添加了 7 行 (13 - 6)。
所以问题是,使用正则表达式或其他一些 Ruby 字符串方法,如何轻松提取上述信息?
即我如何轻松提取此信息:
两个行号(即只是 1827 或 878),然后我可以加上 + 3 以确定我关心的实际内联号。它必须是两者,因为两条线可能并不总是相同的。- 受影响的行数(也就是上面示例中
,
之后的7
、15
或13
) - 当我这样做时,我如何确保跟踪每个操作的操作(添加或删除)。
我尝试对字符串进行切片并直接找到一个字符——例如myString[3]
这给了我 -
,但这是它唯一可靠工作的字符,因为行号可以是 1、10、100、1000、10000 等。所以唯一的方法就是扫描字符串然后解析它。
编辑 1
添加一些代码来展示我的尝试。
假设我在名为 @diff_lines
:
@diff_lines.each do |diff_line|
if diff_line.start_with?("@@")
del_line_num_start = diff_line.split(/@@ /).second.split.first.split(/-/).second.split(/,/).first.to_i + 3
num_deleted_lines = diff_line.split(/@@ /).second.split.first.split(/-/).second.split(/,/).second.to_i - 6
add_line_num_start = diff_line.split(/@@ /).second.split.second.split(/\+/).second.split(/,/).first.to_i + 3
num_added_lines = diff_line.split(/@@ /).second.split.second.split(/\+/).second.split(/,/).second.to_i - 6
如您所见,上面的方法有效....但看起来很可怕,而且显然不是很干。
理想情况下,我希望能够实现同样的事情,但更干净。
总体思路是编写一个包含捕获组 ((...)
) 的正则表达式,以将该字符串分解为有用的内容。例如:
diff_line.match(/\A@@\s+\-(\d+),(\d+)\s+\+(\d+),(\d+)\s+@@/)
这会在成功匹配时产生一个 MatchData 对象。然后,您可以将其应用于某些变量,例如:
if (m = diff_line.match(...))
a_start, a_len, b_start, b_len = m[1..4].map(&:to_i)
end
然后你可以用这些数字做任何你需要做的计算。
如果您在想象正则表达式的作用时遇到困难,请尝试使用像 Rubular 这样的工具来更好地说明内部结构。