2010-08-17 27 views
10

Tôi đang cố gắng xây dựng một phương pháp mở rộng chuỗi để cắt chuỗi thành một độ dài nhất định nhưng không bị ngắt từ. Tôi muốn kiểm tra xem liệu có bất cứ thứ gì được xây dựng trong khung hoặc một phương pháp thông minh hơn tôi hay không. Đây là của tôi cho đến nay (chưa được kiểm tra kỹ lưỡng):Xây dựng một chức năng cắt xén chuỗi thông minh trong C#

public static string SmartTrim(this string s, int length) 
     { 
      StringBuilder result = new StringBuilder(); 

      if (length >= 0) 
      { 
       if (s.IndexOf(' ') > 0) 
       { 
        string[] words = s.Split(' '); 
        int index = 0; 

        while (index < words.Length - 1 && result.Length + words[index + 1].Length <= length) 
        { 
         result.Append(words[index]); 
         result.Append(" "); 
         index++; 
        } 

        if (result.Length > 0) 
        { 
         result.Remove(result.Length - 1, 1); 
        } 
       } 
       else 
       { 
        result.Append(s.Substring(0, length)); 
       } 
      } 
      else 
      { 
       throw new ArgumentOutOfRangeException("length", "Value cannot be negative."); 
      } 

      return result.ToString(); 
     } 
+1

tôi sẽ không chia nhỏ. tôi sẽ lặp lại chuỗi tìm kiếm từ vỡ tiếp theo. dừng lại nếu vị trí của chu kỳ tìm thấy là sau độ dài đã cho. nếu không, hãy thêm từ đó vào trước trình tạo chuỗi.để tìm từ trước khi tìm được điểm ngắt, bạn sẽ cần phải lưu trữ vị trí của khoảng ngắt được tìm thấy trước đó (hoặc số không). có ý nghĩa? – akonsu

+1

Bạn có thể không quan tâm đến ứng dụng của mình, nhưng hãy nhớ rằng các hàm 'Trim' được xây dựng sẵn đang thực sự kiểm tra' char.IsWhiteSpace', không chỉ là 'không gian'. – Marc

+0

@Marc - lưu ý tốt. Tôi đang hỏi từ ngữ của tôi trong khi gõ nó. –

Trả lời

14

Tôi muốn sử dụng string.LastIndexOf - ít nhất là nếu chúng tôi chỉ quan tâm đến khoảng trắng. Sau đó, không cần phải tạo ra bất kỳ chuỗi trung gian ...

Như được nêu ra chưa được kiểm tra:

public static string SmartTrim(this string text, int length) 
{ 
    if (text == null) 
    { 
     throw new ArgumentNullException("text"); 
    } 
    if (length < 0) 
    { 
     throw new ArgumentOutOfRangeException(); 
    } 
    if (text.Length <= length) 
    { 
     return text; 
    } 
    int lastSpaceBeforeMax = text.LastIndexOf(' ', length); 
    if (lastSpaceBeforeMax == -1) 
    { 
     // Perhaps define a strategy here? Could return empty string, 
     // or the original 
     throw new ArgumentException("Unable to trim word"); 
    } 
    return text.Substring(0, lastSpaceBeforeMax);   
} 

mã kiểm tra:

public class Test 
{ 
    static void Main() 
    { 
     Console.WriteLine("'{0}'", "foo bar baz".SmartTrim(20)); 
     Console.WriteLine("'{0}'", "foo bar baz".SmartTrim(3)); 
     Console.WriteLine("'{0}'", "foo bar baz".SmartTrim(4)); 
     Console.WriteLine("'{0}'", "foo bar baz".SmartTrim(5)); 
     Console.WriteLine("'{0}'", "foo bar baz".SmartTrim(7)); 
    } 
} 

Kết quả:

'foo bar baz' 
'foo' 
'foo' 
'foo' 
'foo bar' 
+0

Vì vậy, làm thế nào để bạn refactor nếu yêu cầu là bất kỳ từ nghỉ, không chỉ là một không gian? Cụ thể là phổ biến nhất (nơi một từ có thể bị vỡ, nhưng nhân vật không có khoảng trắng xung quanh nó) là dấu nối ... Chỉ tò mò thôi. – AllenG

+1

@AllenG: Nếu nó vẫn còn trong một tập hợp nhỏ, 'text.LastIndexOfAny (Delimiters)' sẽ là tùy chọn tốt nhất. –

2

Làm thế nào về một giải pháp dựa trên Regex? Bạn có thể sẽ muốn kiểm tra một số chi tiết, và làm một số kiểm tra giới hạn; nhưng đây là những gì mùa xuân đến tâm trí của tôi:

using System; 
using System.Text.RegularExpressions; 

namespace Stackoverflow.Test 
{ 
    static class Test 
    { 
     private static readonly Regex regWords = new Regex("\\w+", RegexOptions.Compiled); 

     static void Main() 
     { 
      Console.WriteLine("The quick brown fox jumped over the lazy dog".SmartTrim(8)); 
      Console.WriteLine("The quick brown fox jumped over the lazy dog".SmartTrim(20)); 
      Console.WriteLine("Hello, I am attempting to build a string extension method to trim a string to a certain length but with not breaking a word. I wanted to check to see if there was anything built into the framework or a more clever method than mine".SmartTrim(100)); 
     } 

     public static string SmartTrim(this string s, int length) 
     { 
      var matches = regWords.Matches(s); 
      foreach (Match match in matches) 
      { 
       if (match.Index + match.Length > length) 
       { 
        int ln = match.Index + match.Length > s.Length ? s.Length : match.Index + match.Length; 
        return s.Substring(0, ln); 
       } 
      } 
      return s; 
     } 
    } 
} 
2

Hãy thử điều này. Nó không an toàn, sẽ không phá vỡ nếu độ dài dài hơn chuỗi và liên quan đến thao tác chuỗi nhỏ hơn.

Chỉnh sửa: Mỗi đề xuất, tôi đã xóa chuỗi trung gian. Tôi sẽ để lại câu trả lời vì nó có thể hữu ích trong trường hợp ngoại lệ không được mong muốn.

public static string SmartTrim(this string s, int length) 
{ 
    if(s == null || length < 0 || s.Length <= length) 
     return s; 

    // Edit a' la Jon Skeet. Removes unnecessary intermediate string. Thanks! 
    // string temp = s.Length > length + 1 ? s.Remove(length+1) : s; 
    int lastSpace = s.LastIndexOf(' ', length + 1); 
    return lastSpace < 0 ? string.Empty : s.Remove(lastSpace); 
} 
+0

Không tệ, nhưng vẫn tạo ra một chuỗi trung gian trong một số trường hợp :) –

+0

Tôi nghĩ bạn có thể cũng làm như vậy: 's.LastIndexOf ('', length);' Và bạn không phải thực hiện chuỗi 'string temp = ...'. – mlsteeves

+0

@mlsteeves: Đồng ý. Giải pháp @ Jon xử lý 'LastIndexOf' tốt hơn. Tôi đã không biết về việc ghi đè khác. – kbrimington

1
string strTemp = "How are you doing today"; 
int nLength = 12; 
strTemp = strTemp.Substring(0, strTemp.Substring(0, nLength).LastIndexOf(' ')); 

tôi nghĩ rằng nên làm điều đó. Khi tôi chạy nó, nó kết thúc bằng "Bạn thế nào".

Vì vậy, chức năng của bạn sẽ là:

public static string SmartTrim(this string s, int length) 
{ 
    return s.Substring(0, s.Substring(0, length).LastIndexOf(' '));; 
} 

Tôi chắc chắn sẽ thêm một số xử lý ngoại lệ mặc dù, như đảm bảo độ dài số nguyên không lớn hơn độ dài chuỗi và không nhỏ hơn 0.

+1

Điều này sẽ không thành công trong các trường hợp khác nhau, ví dụ: nếu độ dài dài hơn bạn cần hoặc là một từ chính xác độ dài phù hợp hoặc không thể được cắt thành công. –

+0

Vâng, bạn đã đưa ra nhận xét đó khi tôi đang chỉnh sửa. :) Tôi figured tôi woudl để xử lý ngoại lệ cho anh ta. – XstreamINsanity

1

Bắt buộc LINQ một lớp lót, nếu bạn chỉ quan tâm đến khoảng trắng là ranh giới từ:

return new String(s.TakeWhile((ch,idx) => (idx < length) || (idx >= length && !Char.IsWhiteSpace(ch))).ToArray()); 
0

Tôi sẽ quăng vào một số Linq tốt đẹp mặc dù những người khác đã trả lời câu hỏi này uately:

public string TrimString(string s, int maxLength) 
{ 
    var pos = s.Select((c, idx) => new { Char = c, Pos = idx }) 
     .Where(item => char.IsWhiteSpace(item.Char) && item.Pos <= maxLength) 
     .Select(item => item.Pos) 
     .SingleOrDefault(); 

    return pos > 0 ? s.Substring(0, pos) : s; 
} 

tôi rời ra tham số kiểm tra mà những người khác có chỉ đơn thuần là để nhấn mạnh các mã quan trọng ...

1

Sử dụng như thế này

var substring = source.GetSubstring(50, new string[] { " ", "." })

Phương pháp này có thể nhận được một tiểu chuỗi dựa trên một hoặc nhiều ký tự phân cách

public static string GetSubstring(this string source, int length, params string[] options) 
    { 
     if (string.IsNullOrWhiteSpace(source)) 
     { 
      return string.Empty; 
     } 

     if (source.Length <= length) 
     { 
      return source; 
     } 

     var indices = 
      options.Select(
       separator => source.IndexOf(separator, length, StringComparison.CurrentCultureIgnoreCase)) 
       .Where(index => index >= 0) 
       .ToList(); 

     if (indices.Count > 0) 
     { 
      return source.Substring(0, indices.Min()); 
     } 

     return source; 
    } 
Các vấn đề liên quan