Ruby正则表达式:同时捕获和删除的有效方法
我正在使用ruby中的正则表达式从代码文件中删除注释。代码是C++(但我认为这不是相关的),文件包含了类似的内容:Ruby正则表达式:同时捕获和删除的有效方法,ruby,regex,Ruby,Regex,我正在使用ruby中的正则表达式从代码文件中删除注释。代码是C++(但我认为这不是相关的),文件包含了类似的内容: /* Hello! I'm a comment! */ int main(int argc, char* argv[]) { Foo foo; foo.bar(); return 0; } text.scan(UGLY_COMMENTS_REGEX).each do |m| m.method_for_printing_matched_comme
/*
Hello! I'm a comment!
*/
int main(int argc, char* argv[])
{
Foo foo;
foo.bar();
return 0;
}
text.scan(UGLY_COMMENTS_REGEX).each do |m|
m.method_for_printing_matched_comment
text = text.gsub(m,'');
end
我的目标是从代码中删除注释,同时解析注释,现在我可以通过捕获然后删除来实现:
text.scan(UGLY_COMMENTS_REGEX).each do |m|
m.method_for_printing_matched_comment
end
text = text.gsub(UGLY_COMMENTS_REGEX,'');
我想到的另一种选择是为每个正则表达式匹配执行gsub
,而不是使用完整的正则表达式,例如:
/*
Hello! I'm a comment!
*/
int main(int argc, char* argv[])
{
Foo foo;
foo.bar();
return 0;
}
text.scan(UGLY_COMMENTS_REGEX).each do |m|
m.method_for_printing_matched_comment
text = text.gsub(m,'');
end
这个(也是次优的)备选方案的问题是,当匹配包含“组”时,例如m[0],m[1]
由于这样做似乎效率极低,我想知道是否有任何方法可以只进行一次匹配(用于捕获和删除)。(以及其他String#gsub
,String#sub!
,String#sub
)接受可选块(将使用匹配的字符串调用)。所以你可以这样做:
text.gsub!(UGLY_COMMENTS_REGEX) { |m|
puts m # to print the matched comment / OR m.method_for_printing_matched_comment
'' # Return value is used as a replacement string; effectively remove the comment
}
我认为以下措施应该有效 代码
def strip_comments(str)
comments = []
[str.split(/[ \t]*\/\*|\*\/(?:[ \t]*\n?/)
.select.with_index {|ar,i| i.even? ? true : (comments << ar.strip; false)}
.join,
comments]
end
str =<<_
/*
Hello! I'm a comment!
*/
int main(int argc, char* argv[])
{
Foo foo;
/* Let's get this one too */
foo.bar();
return 0;
}
_
cleaned_code, comments = strip_comments(str)
puts cleaned_code
# int main(int argc, char* argv[])
# {
# Foo foo;
# foo.bar();
# return 0;
# }
puts comments
# Hello! I'm a comment!
# Let's get this one too
拆分/*
或*/
上的字符串将创建一个数组,其中每个其他元素都是注释的文本。数组的第一个元素将是要保留的文本,如果字符串以注释开头,则该元素将等于“
”。为了保留正确的格式(我希望如此),我还剥离了/*
前面的任何空格或制表符(但不是换行符),以及*/
后面的任何制表符或空格,以及换行符
b = str.split(/[ \t]*\/\*|\*\/(?:[ \t]*\n)?/)
#=> ["",
# "\n Hello! I'm a comment!\n",
# "\nint main(int argc, char* argv[])\n{\n Foo foo;\n",
# " Let's get this one too ",
# " foo.bar();\n return 0;\n}\n"]
我们希望选择非注释的元素,同时保留后者:
enum0 = b.select
#=> #<Enumerator: [
# "",
# "\n Hello! I'm a comment!\n",
# "\nint main(int argc, char* argv[])\n{\n Foo foo;\n",
# " Let's get this one too ",
# " foo.bar();\n return 0;\n}\n"]:select>
使用数组#each
执行枚举器及其块:
c = enum1.each {|ar,i| i.even? ? true : (comments << ar.strip; false)}
#=> ["",
# "\nint main(int argc, char* argv[])\n{\n Foo foo;\n",
# " foo.bar();\n return 0;\n}\n"]
连接c
的元素:
cleaned_text = c.join
#=> "\nint main(int argc, char* argv[])\n{\n Foo foo;\n foo.bar();\n return 0;\n}\n"
并返回:
[cleaned_text, comments]
如上所示
编辑:稍微好一点,我想:
def strip_comments(str)
a = str.split(/[ \t]*\/\*|\*\/(?:[ \t]*\n)?/)
a << "" if a.size.odd?
cleaned, comments = a.each_pair.transpose
[cleaned.join, comments.map(&:strip)]
end
def条带注释(str)
a=str.split(/[\t]*\/\*\\*\/(?:[\t]*\n)?/)
A.
[cleaned_text, comments]
def strip_comments(str)
a = str.split(/[ \t]*\/\*|\*\/(?:[ \t]*\n)?/)
a << "" if a.size.odd?
cleaned, comments = a.each_pair.transpose
[cleaned.join, comments.map(&:strip)]
end