Trim String

S

shapper

Hello,

I am using a method to truncate a string without breaking words and
when the string is truncated ellipses (...) should be added.

With:
Truncate(true, 108, "Article Long Title - The development of an
ASP.NET MVC RC2 with an SQL Database and C# ")

I get the error:
Index and length must refer to a location within the string.
Parameter name: length

public static String Truncate(Boolean ellipsis, Int32 length,
String text) {
String trimmed = text.Substring(0,
length);
if (text.Length <= length || length == 0 || text[length -
1].Equals(' '))
return trimmed;
Int32 i = length;
while (i > 0 && !trimmed[i - 1].Equals(' ')) i--;
return ellipsis ? String.Concat(trimmed.Substring(0, i), " ...
") : trimmed.Substring(0, i);
} // Truncate

What am I missing?

Thanks,
Miguel
 
F

Family Tree Mike

shapper said:
Hello,

I am using a method to truncate a string without breaking words and
when the string is truncated ellipses (...) should be added.

With:
Truncate(true, 108, "Article Long Title - The development of an
ASP.NET MVC RC2 with an SQL Database and C# ")

I get the error:
Index and length must refer to a location within the string.
Parameter name: length

public static String Truncate(Boolean ellipsis, Int32 length,
String text) {
String trimmed = text.Substring(0,
length);
if (text.Length <= length || length == 0 || text[length -
1].Equals(' '))
return trimmed;
Int32 i = length;
while (i > 0 && !trimmed[i - 1].Equals(' ')) i--;
return ellipsis ? String.Concat(trimmed.Substring(0, i), " ...
") : trimmed.Substring(0, i);
} // Truncate

What am I missing?

Thanks,
Miguel


Shouldn't your two return statements be identical? In other words, why
wouldn't you append ellipsis at the end of the first condition?
 
P

Pavel Minaev

I am using a method to truncate a string without breaking words and
when the string is truncated ellipses (...) should be added.

With:
Truncate(true, 108, "Article Long Title - The development of an
ASP.NET MVC RC2 with an SQL Database and C# ")

I get the error:
Index and length must refer to a location within the string.
Parameter name: length

    public static String Truncate(Boolean ellipsis, Int32 length,
String text) {
      String trimmed = text.Substring(0,
length);
      if (text.Length <= length || length == 0 || text[length-
1].Equals(' '))
        return trimmed;
      Int32 i = length;
      while (i > 0 && !trimmed[i - 1].Equals(' ')) i--;
      return ellipsis ? String.Concat(trimmed.Substring(0, i), " ....
") : trimmed.Substring(0, i);
    } // Truncate

What am I missing?

It would help if you told the number of the line at which the
exception is thrown. From what I can see, I'd expect this to be the
very first call to Substring(), and the reason would be that your
method has already got an invalid value for "length" as input. Check
the calling code.
 
S

shapper

I am using a method to truncate a string without breaking words and
when the string is truncated ellipses (...) should be added.
With:
Truncate(true, 108, "Article Long Title - The development of an
ASP.NET MVC RC2 with an SQL Database and C# ")
I get the error:
Index and length must refer to a location within the string.
Parameter name: length
    public static String Truncate(Boolean ellipsis, Int32 length,
String text) {
      String trimmed = text.Substring(0,
length);
      if (text.Length <= length || length == 0 || text[length -
1].Equals(' '))
        return trimmed;
      Int32 i = length;
      while (i > 0 && !trimmed[i - 1].Equals(' ')) i--;
      return ellipsis ? String.Concat(trimmed.Substring(0, i), " ....
") : trimmed.Substring(0, i);
    } // Truncate
What am I missing?

It would help if you told the number of the line at which the
exception is thrown. From what I can see, I'd expect this to be the
very first call to Substring(), and the reason would be that your
method has already got an invalid value for "length" as input. Check
the calling code.

Hi,

I followed your advices and it is working:

// Truncate
public static String Truncate(Boolean ellipsis, Int32 length,
String text) {

if (text.Length < length || length == 0 || length == 0) return
text;
String trimmed = text.Substring(0, length);
Int32 i = trimmed.LastIndexOf(' ');
trimmed = trimmed.Substring(0, i);
return ellipsis ? trimmed + '…' : trimmed;

} // Truncate

What do you think?

On VS2008 the '...' looks like '_' ... The only way I was able to
write the ellipses as a char was copying it from Word.
Not sure if this is the right way to do it ... I also tried '…'
but it didn't work ...

Thank You,
Miguel
 
S

shapper

I suspect you still have some bugs:

     -- You have the expression "length == 0" twice in your first "if"  
statement.  That's different from what you were checking for in your  
previous post.  At the very least, one is redundant, and it's possible  
that you intended to use some other condition as the second one.

     -- You aren't checking the return value for LastIndexOf(), so a string  
without any spaces in it is likely to break your code.

     -- Once you fix that issue, then you have the issue that a space-less  
string with an ellipsis added is going to exceed the "length" specified by  
the caller, by one character.

Other than that, it looks much better.  :)

If you want to specify the '…' character by Unicode value, I think you  
want '\x2026', rather than the syntax you tried.

Pete

Not sure if this is the most elegant code but it is working and I
tried to solve the issues you mentioned:

// Trim
public static String Trim(Boolean ellipsis, Int32 length, String
text) {

// Check text
if (text.Length < length || length == 0) return text;

// Trim
String trimmed = text.Substring(0, ellipsis ? length - 1 :
length);
Int32 i = trimmed.LastIndexOf(' ');
if (i != -1)
trimmed = trimmed.Substring(0, i);
return ellipsis ? trimmed + '\x2026' : trimmed;

} // Trim
 
P

Pavel Minaev

    // Trim
    public static String Trim(Boolean ellipsis, Int32 length, String
text) {

      // Check text
      if (text.Length < length || length == 0) return text;

It looks rather non-obvious to me that for length==0, the string is
not trimmed at all. A more reasonable approach would be to return
String.Empty if ellipsis==false, or throw ArgumentOutOfRange exception
if it is true (since you obviously can't satisfy the request then).
      // Trim
      String trimmed = text.Substring(0, ellipsis ? length - 1 :
length);
      Int32 i = trimmed.LastIndexOf(' ');
      if (i != -1)
        trimmed = trimmed.Substring(0, i);
      return ellipsis ? trimmed + '\x2026' : trimmed;

Another observation: if the string starts with one or more spaces,
then it will be replaced with "..." entirely, even if most of the
string is meaningful text. I remember that your initial requirement
was to break at word boundaries, but I think that from the usability
point of view it's better not to break at less than half of the
trimmed string - it loses too much info, and if you are trying to fit
it to some display area, it will become too short.

Another corner case is that a single-char string will also be entirely
replaced by "...".
 
S

shapper

It looks rather non-obvious to me that for length==0, the string is
not trimmed at all. A more reasonable approach would be to return
String.Empty if ellipsis==false, or throw ArgumentOutOfRange exception
if it is true (since you obviously can't satisfy the request then).

I followed your suggestion and updated my code ... if i understood you
right.
Another observation: if the string starts with one or more spaces,
then it will be replaced with "..." entirely, even if most of the
string is meaningful text. I remember that your initial requirement
was to break at word boundaries, but I think that from the usability
point of view it's better not to break at less than half of the
trimmed string - it loses too much info, and if you are trying to fit
it to some display area, it will become too short.

Another corner case is that a single-char string will also be entirely
replaced by "...".

I am a little bit lost about this part.
I tried to make a few changes but my code stops working.
Could you help me out?

This is my updated code:

public static String Trim(Boolean ellipsis, Int32 length, String
text) {

// Check length
if (length == 0)
if (ellipsis)
throw new ArgumentOutOfRangeException();
else
return String.Empty;

// Check text
if (text.Length < length) return text;

// Trim
String trimmed = text.Substring(0, ellipsis ? length - 1 :
length);
Int32 i = trimmed.LastIndexOf(' ');
if (i != -1)
trimmed = trimmed.Substring(0, i);
return ellipsis ? trimmed + '\x2026' : trimmed;

} // Trim

Thank You,
Miguel
 
S

shapper

[...]
Another observation: if the string starts with one or more spaces,
then it will be replaced with "..." entirely, even if most of the
string is meaningful text.

If the string has spaces _only_ at the beginning, that is.  It's true,
this could be a problem.  How best to address it would depend on exactly
what the actual requirements are, which we aren't privy to.
I remember that your initial requirement
was to break at word boundaries, but I think that from the usability
point of view it's better not to break at less than half of the
trimmed string - it loses too much info, and if you are trying to fit
it to some display area, it will become too short.

If there's a hard limit on character count, arbitrarily setting the
minimum length at 50% of the original isn't going to work.

Again, it all depends on what the actual requirements are.  In some
scenarios, trimming the string from the middle, leaving the beginning and
end, often works well.  But, it's possible in this case trimming always
  from the end might be fine too.
Another corner case is that a single-char string will also be entirely
replaced by "...".

Not unless it exceeds the target length, and the remainder is entirely
spaces.

Sometimes, corner cases are best addressed by telling the caller to not
pass silly data.  :)

Pete

The only problem that I predict I might have is if the text starts
with a space ... not because it is intended but when the user creates
a new article it might insert a space in the beginning so I would like
to avoid this mistake to create a wrong trimming.

How can I prevent it?

Thank You,
Miguel
 
S

shapper

Don't let the user do that?

There are a number of _potential_ solutions.  Not knowing the specific  
scenario here, it's not possible for anyone other than you to identify  
what solution is appropriate in _your_ case.  All of the solutions are  
likely to fall into one of two basic approaches though: don't allow the  
input that doesn't meet your criteria; or handle the input by modifying it  
to suit what you think is correct.

Pete

Isn't there a way to remove all white spaces on the start of a
string ...
.... I think I've used something like that before but I can't find it.

I could remove all white spaces at the begining of the text and apply
my code only after, or not?

Thanks,
Miguel
 
S

shapper

You could.  Whether that's appropriate for what you're doing, I couldn't  
say.  But if you think it is, then sure...you can do that.

Pete

Thank You Pete. It was that.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top