将存储在字符串中的代码行取消缩进的有效方法
本文关键字:取消 缩进 有效 方法 代码 字符串 存储 | 更新日期: 2023-09-27 18:15:06
我有一个包含代码的string[]
。每行包含一些前导空格。我需要在不改变现有格式的情况下尽可能地"取消缩进"代码。
例如我的string[]
的内容可能是
公共类MyClass{private bool MyMethod(字符串){返回s == ";}}之前我想找到一种相当优雅和有效的方法(LINQ?)将其转换为
公共类MyClass{private bool MyMethod(字符串){返回s == ";}} 之前要清楚,我正在寻找
IEnumerable<string> UnindentAsMuchAsPossible(string[] content) { return ???; }
基于Tim Schmelter的回答:
static IEnumerable<string> UnindentAsMuchAsPossible(IEnumerable<string> lines, int tabWidth = 4)
{
if (!lines.Any())
{
return Enumerable.Empty<string>();
}
var minDistance = lines
.Where(line => line.Length > 0)
.Min(line => line
.TakeWhile(Char.IsWhiteSpace)
.Sum(c => c == ''t' ? tabWidth : 1));
var spaces = new string(' ', tabWidth);
return input
.Select(line => line.Replace("'t", spaces))
.Select(line => line.Substring(Math.Min(line.Length, minDistance)));
}
这句柄:
- 制表符
- 包含空行的源代码
只需计算第一行的前导空格数,然后从每行开头"删除"这些字符:
IEnumerable<string> UnindentAsMuchAsPossible(string[] content)
{
int spacesOnFirstLine = content[0].TakeWhile(c => c == ' ').Count();
return content.Select(line => line.Substring(spacesOnFirstLine));
}
应该可以:
static IEnumerable<string> UnindentAsMuchAsPossible(IEnumerable<string> input)
{
int minDistance = input.Min(l => l.TakeWhile(Char.IsWhiteSpace).Count());
return input.Select(l => l.Substring(minDistance));
}
将代码向左移动,所有行都有相同数量的空格。
例如:string testString = @"
public class MyClass
{
private bool MyMethod(string s)
{
return s == "";
}
}";
string[] lines = testString.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
string[] unindentedArray = UnindentAsMuchAsPossible(lines).ToArray();
使用一点LINQ和Regex来找到最短的缩进,然后从所有行中删除该数量的字符。
string[] l_lines = {
" public class MyClass",
" {",
" private bool MyMethod(string s)",
" {",
" return s == '"'";",
" }",
" }"
};
int l_smallestIndentation =
l_lines.Min( s => Regex.Match( s, "^''s*" ).Value.Length );
string[] l_result =
l_lines.Select( s => s.Substring( l_smallestIndentation ) )
.ToArray();
foreach ( string l_line in l_result )
Console.WriteLine( l_line );
打印:
public class MyClass
{
private bool MyMethod(string s)
{
return s == "";
}
}
程序将扫描数组中的所有字符串。如果可以假设第一行缩进最少,那么可以通过只扫描第一行来提高性能:
int l_smallestIndentation =
Regex.Match( l_lines[0], "^''s*" ).Value.Length;
还要注意,这将把制表符("'t"
)作为单个字符处理。如果有制表符和空格的混合,那么反转缩进可能会很棘手。处理这个问题最简单的方法是在运行上面的代码之前,用适当数量的空格(通常是4个,尽管各个应用程序的差异很大)替换所有制表符实例。
也可以修改上面的代码,为制表符赋予额外的权重。此时,正则表达式就没有多大用处了。
string[] l_lines = {
"'t't'tpublic class MyClass",
" {",
" private bool MyMethod(string s)",
" {",
" 't 't'treturn s == '"'";",
" }",
"'t't't}"
};
int l_tabWeight = 8;
int l_smallestIndentation =
l_lines.Min
(
s => s.ToCharArray()
.TakeWhile( c => Char.IsWhiteSpace( c ) )
.Select( c => c == ''t' ? l_tabWeight : 1 )
.Sum()
);
string[] l_result =
l_lines.Select
(
s =>
{
int l_whitespaceToRemove = l_smallestIndentation;
while ( l_whitespaceToRemove > 0 )
{
l_whitespaceToRemove -= s[0] == ''t' ? l_tabWeight : 1;
s = s.Substring( 1 );
}
return s;
}
).ToArray();
打印(假设您的控制台窗口的标签宽度为8):
public class MyClass
{
private bool MyMethod(string s)
{
return s == "";
}
}
您可能需要修改此代码以处理边缘情况,例如零长度行或仅包含空格的行。
这将首先找到最小标识,然后为每行删除该数量的空格。
var code = new [] { " foo", " bar" };
var minIndent = code.Select(line => line.TakeWhile(ch => ch == ' ').Count()).Min();
var formatted = code.Select(line => line.Remove(0, minIndent));
可以在一个表达式中编写所有内容,但是虽然它在功能上更优雅,但我认为minIndent
变量使代码更具可读性。
匹配你想要的方法接口:
IEnumerable<string> UnindentAsMuchAsPossible(string[] content)
{
int minIndent = content.Select(s => s.TakeWhile(c => c == ' ').Count()).Min();
return content.Select(s => s.Substring(minIndent)).AsEnumerable();
}
获取所有行的最小缩进(假设只有空格,没有制表符),然后从每行开始去掉minIndent
空格,并返回IEnumerable
。