我的输入由一串不确定的长度和内容组成。我需要在开头和结尾修剪所有空格、字符
#
\t
和片段//
/*
*/
。所有这些符号和字符集都相继出现。如果他们之间还有其他事情,你需要停下来。
例子:
"///g, hhh/ , test" ===> "/g, hhh/ , test"
"//*g, hhh/ , test " ===> "*g, hhh/ , test"
"#/test" ===> "/test"
"hello //" ===> "hello"
重要说明: 我需要知道我在开头修剪了多少个字符,在最后修剪了多少个字符。
另外,我不想使用正则表达式,因为这段代码对性能非常敏感。据我所知,正则表达式非常慢。但是,如果我的任务不能用循环完成,或者类似的事情非常困难——我准备使用正则表达式。
到目前为止,我已经尝试过这样的代码。由于某些符号代表两个相互跟随的字符,因此任务变得复杂。
private const char specialSymbol_1 = '/';
private const char specialSymbol_2 = '*';
private const char specialSymbol_3 = '#';
private void ObserveTrim(ref string target, ref int start, ref int end) {
int s = 0; int e = 0;
for (int i = 0; i < target.Length; ++i) {
char c = target[i];
bool flag = false;
if (target.Length > 1) {
if (i == 0) {
flag = c == specialSymbol_1 && target[i + 1] == specialSymbol_1 ||
c == specialSymbol_1 && target[i + 1] == specialSymbol_2 ||
c == specialSymbol_2 && target[i + 1] == specialSymbol_1;
}
else if (i == target.Length - 1) {
flag = c == specialSymbol_1 && target[i - 1] == specialSymbol_1 ||
c == specialSymbol_1 && target[i - 1] == specialSymbol_2 ||
c == specialSymbol_2 && target[i - 1] == specialSymbol_1;
}
else {
flag = c == specialSymbol_1 && target[i + 1] == specialSymbol_1 ||
c == specialSymbol_1 && target[i - 1] == specialSymbol_1 ||
c == specialSymbol_1 && target[i + 1] == specialSymbol_2 ||
c == specialSymbol_1 && target[i - 1] == specialSymbol_2;
}
}
if (flag) continue;
if (!char.IsWhiteSpace(c) && c != specialSymbol_3) {
s = i;
break;
}
}
for (int i = target.Length - 1; i >= 0; --i) {
char c = target[i];
bool flag = false;
if (target.Length > 1) {
if (i == 0) {
flag = c == specialSymbol_1 && target[i + 1] == specialSymbol_1 ||
c == specialSymbol_1 && target[i + 1] == specialSymbol_2 ||
c == specialSymbol_2 && target[i + 1] == specialSymbol_1;
}
else if (i == target.Length - 1) {
flag = c == specialSymbol_1 && target[i - 1] == specialSymbol_1 ||
c == specialSymbol_1 && target[i - 1] == specialSymbol_2 ||
c == specialSymbol_2 && target[i - 1] == specialSymbol_1;
}
else {
flag = c == specialSymbol_1 && target[i + 1] == specialSymbol_1 ||
c == specialSymbol_1 && target[i - 1] == specialSymbol_1 ||
c == specialSymbol_1 && target[i + 1] == specialSymbol_2 ||
c == specialSymbol_1 && target[i - 1] == specialSymbol_2;
}
}
if (flag) continue;
if (!char.IsWhiteSpace(c) && c != specialSymbol_3) {
e = target.Length - 1 - i;
break;
}
}
start += s;
end -= e;
target = target.Substring(s, target.Length - s - e);
}
但是这段代码没有按预期工作。 例子:
"///g, hhh/ , test" ===> "g, hhh/ , test"
"/*g, hhh/ , test" ===> "*g, hhh/ , test"
这些只是他错误工作的几个例子,实际上有几十个。
它根本不考虑某些字符或它们的顺序。我不擅长这样的算法,欢迎任何帮助。
虽然所有字符串都指向
trim
,但我建议用StartsWith
和EndsWith
检查所有字符串。在 ReadOnlySpan<char>
的帮助下,我们可以在不创建许多不需要的子字符串的情况下做到这一点。
既然你想得到
3
参数-result
(修剪字符串),从left
和right
中删除了多少个符号,让我们将它们组合成一个元组:
代码:
public static (string result, int left, int right) MyTrim(
string value, params string[] trim) {
if (string.IsNullOrEmpty(value) || trim is null || trim.Length == 0)
return (value, 0, 0);
int trimmedLeft = 0;
int trimmedRight = 0;
var span = value.AsSpan();
for (bool keep = true; keep; ) {
keep = false;
foreach (var item in trim)
if (!string.IsNullOrEmpty(item) && span.StartsWith(item)) {
trimmedLeft += item.Length;
span = span.Slice(item.Length);
keep = true;
break;
}
}
for (bool keep = true; keep; ) {
keep = false;
foreach (var item in trim)
if (!string.IsNullOrEmpty(item) && span.EndsWith(item)) {
trimmedRight += item.Length;
span = span.Slice(0, span.Length - item.Length);
keep = true;
break;
}
}
return (span.ToString(), trimmedLeft, trimmedRight);
}
用法:
string value = "///g, hhh/ , test";
(string result, int left, int right) = MyTrim(
value, " ", "#", "\t", "//", "/*", "*/");
演示:
using System.Linq;
...
string[] tests = new string[] {
"///g, hhh/ , test",
"//*g, hhh/ , test ",
"#/test",
"hello //",
};
var report = string.Join(Environment.NewLine, tests
.Select(test => (test, result : MyTrim(test, " ", "#", "\t", "//", "/*", "*/")))
.Select(pair => $"{pair.test,30} ===> {pair.result.result} (left: {pair.result.left}; right: {pair.result.right}) "));
Console.WriteLine(report);
输出:
///g, hhh/ , test ===> /g, hhh/ , test (left: 2; right: 0)
//*g, hhh/ , test ===> *g, hhh/ , test (left: 2; right: 1)
#/test ===> /test (left: 1; right: 0)
hello // ===> hello (left: 0; right: 4)
尽管 Dmitry 的回答非常详尽,但我无法以其原始形式应用它,因为它受到编译器的限制。
我正在为一个程序编写脚本,我什至不知道它支持什么语言版本。在这方面,我重写了代码并只使用了我设法编译的那些结构。我为那些发现自己处于我的情况的人发布此降级。遗憾的是我们不得不牺牲便利性和性能。 但是,我会将他的回答标记为解决方案,因为现代大多数编译器都会处理这段代码。
我还部分编辑了问题,使问题及其解决方案对于遇到类似问题的人来说更具描述性。
谢谢大家的帮助。
private const char specialSymbol_1 = '/';
private const char specialSymbol_2 = '*';
private const char specialSymbol_3 = '#';
private void CheckContent() {
int leftWordStart = ...;
int leftWordEnd = ...;
string leftWord = ...;
MyTrim(ref leftWord, ref leftWordStart, ref leftWordEnd,
new string[6] { " ", "\t", new string(specialSymbol_1, 2), new string(new char[2] {specialSymbol_1, specialSymbol_2}),
new string(new char[2] {specialSymbol_2, specialSymbol_1}), specialSymbol_3.ToString()});
//...
}
private void MyTrim(ref string target, ref int start, ref int end, string[] trim) {
if (string.IsNullOrWhiteSpace(target) || trim == null || trim.Length == 0) return;
int trimmedLeft = 0;
int trimmedRight = 0;
bool keep = true;
while (keep) {
keep = false;
for (int i = 0; i < trim.Length; ++i) {
string item = trim[i];
if (!string.IsNullOrEmpty(item) && target.StartsWith(item)) {
trimmedLeft += item.Length;
target = target.Substring(item.Length);
keep = true;
break;
}
}
}
keep = true;
while (keep) {
keep = false;
for (int i = 0; i < trim.Length; ++i) {
string item = trim[i];
if (!string.IsNullOrEmpty(item) && target.EndsWith(item)) {
trimmedRight += item.Length;
target = target.Substring(0, target.Length - item.Length);
keep = true;
break;
}
}
}
start += trimmedLeft;
end -= trimmedRight;
}
我的问题收到的否决票数量给我留下了深刻的印象,考虑到没有任何重复并且问题本身并不完全标准。