C# 交换两个字符串,忽略每个字符串开头和结尾的空格和特殊字符集

问题描述 投票:0回答:1

我的输入由一串不确定的长度和内容组成。我需要在开头和结尾修剪所有空格、字符

#
\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"

这些只是他错误工作的几个例子,实际上有几十个。

它根本不考虑某些字符或它们的顺序。我不擅长这样的算法,欢迎任何帮助。

更新:

由于我的问题引起了如此大的反对票(我很惊讶),我将把任务扩展到单一方法之外。也许这会把事情搞清楚一点。

我的任务是交换任意两段用逗号分隔的文本。在这样做时,我必须考虑到最里面的括号

{}
[]
()
<>
,并且只在其中移动文本。

在这样做时,我应该只考虑文本本身,而不应该考虑空格,

#
//
/*
*/
等字符。目前,在换行时只考虑字符是行不通的,这个词是连同这些字符一起换行的。这是完整的代码。

using EnvDTE; using EnvDTE80;

public class C : VisualCommanderExt.ICommand {
    public void Run(EnvDTE80.DTE2 DTE, Microsoft.VisualStudio.Shell.Package package) {
        EnvDTE.TextSelection ts = DTE.ActiveDocument.Selection as EnvDTE.TextSelection;
        EnvDTE.TextDocument doc = DTE.ActiveDocument.Object("TextDocument") as EnvDTE.TextDocument;
        EnvDTE.EditPoint p = doc.CreateEditPoint();
        p.MoveToLineAndOffset(ts.TopLine, 1);
        string text = p.GetText(p.LineLength);
        if (!string.IsNullOrWhiteSpace(text)) {
            StatementConstructor c = new StatementConstructor(text, ts);
            c.Process();
            c.Destroy();
        }
    }

    class StatementConstructor {
        private const char openSymbol_1 = '['; private const char openSymbol_2 = '(';
        private const char openSymbol_3 = '<'; private const char openSymbol_4 = '{';
        
        private const char closeSymbol_1 = ']'; private const char closeSymbol_2 = ')';
        private const char closeSymbol_3 = '>'; private const char closeSymbol_4 = '}';
        
        private const char separator = ',';
        
        private const char specialSymbol_1 = '/'; private const char specialSymbol_2 = '*';
        private const char specialSymbol_3 = '#';
        
        private string text;
        private EnvDTE.TextSelection ts;
        
        public StatementConstructor(string text, EnvDTE.TextSelection ts) {
            this.text = text; this.ts = ts;
        }
        
        public void Process() {
            int startIndex = ts.AnchorPoint.LineCharOffset - 1;
            if (CheckTextOnPoint(startIndex)) {
                int start; int end;
                string content = FindContent(startIndex, out start, out end);
                int rightStart; int rightEnd; string rightText; int leftStart; int leftEnd; string leftText;
                if (CheckContent(content, startIndex - start + 1, out rightStart, out rightEnd, out rightText, out leftStart, out leftEnd, out leftText)) {
                    string fullS = text.Substring(0, start)
                    + SwapStrings(content, leftText, leftStart, leftEnd, rightText, rightStart, rightEnd)
                    + text.Substring(end + 1);
                    
                    //var charPos = ts.AnchorPoint.AbsoluteCharOffset - leftText.Length - 2;
                    //ts.GotoLine(ts.AnchorPoint.Line, true);
                    //ts.Insert(fullS, 4);
                    //ts.MoveToAbsoluteOffset(charPos, false);
                    System.Windows.MessageBox.Show(fullS);
                }
            }
        }
        
        private string SwapStrings(string text, string firstText, int firstStart, int firstEnd, string secondText, int secondStart, int secondEnd) {
            string newS = text.Substring(0, firstStart)
            + secondText
            + text.Substring(firstEnd + 1, secondStart - firstEnd - 1)
            + firstText + text.Substring(secondEnd + 1);
            return newS;
        }
        
        private bool CheckContent(string text, int startIndex, out int rightStart, out int rightEnd, out string rightText, out int leftStart, out int leftEnd, out string leftText) {
            rightStart = -1; rightEnd = -1; rightText = null;
            leftStart = -1; leftEnd = -1; leftText = null;
            if (startIndex > text.Length) startIndex = text.Length;
            if (CheckTextOnPointS(text, startIndex)) {
                bool isSepOnPoint = text[startIndex - 1] == separator;
                int leftSep = startIndex == 0 ? -1 : text.LastIndexOf(separator, isSepOnPoint ? startIndex - 2 : startIndex - 1);
                if (leftSep != -1) {    
                    int leftWordIndex = leftSep - 1;
                    int leftWordSep = leftWordIndex <= 0 ? -1 : text.LastIndexOf(separator, leftWordIndex - 1);
                    int leftWordStart = leftWordSep + 1;
                    int leftWordEnd = leftSep - 1;
                    
                    string leftWord = text.Substring(leftWordStart, leftWordEnd - leftWordStart + 1);
                    ObserveTrim(ref leftWord, ref leftWordStart, ref leftWordEnd);
                    
                    int rightSep = isSepOnPoint ? startIndex - 1 : text.IndexOf(separator, startIndex);
                    
                    System.Windows.MessageBox.Show(leftWordStart.ToString() + " " + leftWordEnd.ToString());
                    
                    int rightWordStart = leftSep + 1;
                    int rightWordEnd = rightSep != -1 ? rightSep - 1 : text.Length - 1;
                    
                    string rightWord = text.Substring(rightWordStart, rightWordEnd - rightWordStart + 1);
                    ObserveTrim(ref rightWord, ref rightWordStart, ref rightWordEnd);
                    
                    leftStart = leftWordStart;
                    leftEnd = leftWordEnd;
                    leftText = leftWord;
                    
                    rightStart = rightWordStart;
                    rightEnd = rightWordEnd;
                    rightText = rightWord;
                    return true;
                }
            }
            return false;
        }
        
        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 (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 (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);
        }
        
        private string FindContent(int startIndex, out int startC, out int endC) {
            int start; int end;
            int type = 0;
            if (CheckBounds(startIndex, openSymbol_1, closeSymbol_1, out start, out end)) type = 1;
            
            int newStart; int newEnd;
            if (CheckBounds(startIndex, openSymbol_2, closeSymbol_2, out newStart, out newEnd)) {
                if (newStart >= start && newEnd <= end) { start = newStart; end = newEnd; type = 2; }
            }
            
            if (CheckBounds(startIndex, openSymbol_3, closeSymbol_3, out newStart, out newEnd)) {
                if (newStart >= start && newEnd <= end) { start = newStart; end = newEnd; type = 3; }
            }
            
            if (CheckBounds(startIndex, openSymbol_4, closeSymbol_4, out newStart, out newEnd)) {
                if (newStart >= start && newEnd <= end) { start = newStart; end = newEnd; type = 4; }
            }
            
            startC = type < 1 ? start : start + 1; endC = type < 1 ? end : end - 1;
            
            if (type < 1) return text;
            else return text.Substring(start + 1, end - start - 1);
        }
        
        private bool CheckBounds(int startIndex, char openBound, char closeBound, out int start, out int end) {
            start = 0;
            end = text.Length - 1;
            
            if (startIndex >= text.Length) return false;
            
            bool hasOpen = false; bool hasClose = false;
            
            for (int i = startIndex; i < text.Length; ++i) {
                if (text[i] == closeBound) {
                    end = i;
                    hasClose = true;
                    break;
                }
            }
            
            for (int i = startIndex - 1; i >= 0; --i) {
                if (text[i] == openBound) {
                    start = i;
                    hasOpen = true;
                    break;
                }
            }
            
            return hasOpen && hasClose;
        }
        
        private bool CheckTextOnPointS(string text, int startIndex) {
            return startIndex >= 0 && 
            (startIndex == text.Length ? IsTextS(text[startIndex - 1]) : 
            (startIndex == 0 ? IsTextS(text[startIndex]) : (IsTextS(text[startIndex]) || IsTextS(text[startIndex - 1]))));
        }
        
        private bool IsTextS(char t) {
            return t != separator;
        }
        
        private bool CheckTextOnPoint(int startIndex) {
            return startIndex >= 0 && (startIndex == text.Length ? IsText(text[startIndex - 1]) : (startIndex == 0 ? IsText(text[startIndex]) : (IsText(text[startIndex]) || IsText(text[startIndex - 1]))));
        }
        
        private bool IsText(char t) {
            if (t == openSymbol_1 || t == openSymbol_2 || t == openSymbol_3 || t == openSymbol_4 ||
                    t == closeSymbol_1 || t == closeSymbol_2 || t == closeSymbol_3 || t == closeSymbol_4) {
                return false;
            } else return true;
        }
        
        public void Destroy() {
            ts = null;
        }
    }
}
c# string trim
1个回答
1
投票

虽然所有字符串都指向

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) 

小提琴

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.