いくつかの実用的なStringクラスの拡張
78127 ワード
public
static
class
StringExtensions
{
public
static
string
[] ToPiece(
this
string
text,
int
maxLength)
{
int
pieces
=
(
int
)Math.Ceiling(text.Length
/
(
double
)maxLength);
string
[] result
=
new
string
[pieces];
for
(
int
i
=
0
; i
<
pieces
-
1
; i
++
)
{
result[i]
=
text.Substring(i
*
maxLength, maxLength);
}
result[pieces
-
1
]
=
text.Substring((pieces
-
1
)
*
maxLength);
return
result;
}
public
static
string
Join(
this
string
[] values,
string
joinText)
{
StringBuilder result
=
new
StringBuilder();
if
(values.Length
==
0
)
return
string
.Empty;
result.Append(values[
0
]);
for
(
int
i
=
1
; i
<
values.Length; i
++
)
{
result.Append(joinText);
result.Append(values[i]);
}
return
result.ToString();
}
public
static
string
TrimWithElipsis(
this
string
text,
int
length)
{
if
(text.Length
<=
length)
return
text;
return
text.Substring(
0
, length)
+
"
...
"
;
}
///
<summary>
///
replacement for String.Format
///
</summary>
public
static
string
With(
this
string
format,
params
object
[] args)
{
return
string
.Format(format, args);
}
///
<summary>
///
prettily renders property names
///
</summary>
///
<param name="text"></param>
///
<returns></returns>
public
static
string
Pretty(
this
string
text)
{
return
DeCamel(text).Replace(
"
_
"
,
"
"
);
}
public
static
void
PrettyTest()
{
Console.WriteLine(
"
hello_worldIAmYourNemesis
"
.Pretty());
}
///
<summary>
///
turns HelloWorld into Hello World
///
</summary>
///
<param name="text"></param>
///
<returns></returns>
public
static
string
DeCamel(
this
string
text)
{
return
Regex.Replace(text,
@"
([A-Z])
"
,
@"
$&
"
).Trim();
}
public
static
void
DeCamelTest()
{
Console.WriteLine(
"
HelloWorldIAmYourNemesis
"
.DeCamel());
}
public
static
string
CreateSlug(
this
string
source)
{
var regex
=
new
Regex(
@"
([^a-z0-9\-]?)
"
);
string
slug
=
""
;
if
(
!
string
.IsNullOrEmpty(source))
{
slug
=
source.Trim().ToLower();
slug
=
slug.Replace(
'
'
,
'
-
'
);
slug
=
slug.Replace(
"
---
"
,
"
-
"
);
slug
=
slug.Replace(
"
--
"
,
"
-
"
);
if
(regex
!=
null
)
slug
=
regex.Replace(slug,
""
);
if
(slug.Length
*
2
<
source.Length)
return
""
;
if
(slug.Length
>
100
)
slug
=
slug.Substring(
0
,
100
);
}
return
slug;
}
public
static
string
Truncate(
this
string
src,
int
size)
{
if
(src.Length
<
size)
return
src;
else
return
src.Substring(
0
, size);
//
SubString size
}
public
static
string
EncryptMD5(
this
string
Value)
{
MD5CryptoServiceProvider md5
=
new
MD5CryptoServiceProvider();
byte
[] valueArray
=
System.Text.Encoding.ASCII.GetBytes(Value);
valueArray
=
md5.ComputeHash(valueArray);
StringBuilder sb
=
new
StringBuilder();
for
(
int
i
=
0
; i
<
valueArray.Length; i
++
)
sb.Append(valueArray[i].ToString(
"
x2
"
).ToLower());
return
sb.ToString();
}
public
static
bool
VerifyMD5Hash(
this
string
value,
string
target)
{
string
input
=
value.EncryptMD5();
if
(input.Equals(target))
return
true
;
return
false
;
}
public
static
string
CleanHtmlTags(
this
string
s)
{
return
s.CleanHtmlTags(
null
);
}
private
static
readonly
Regex tagRegex
=
new
Regex(
"
<[^<>]*>
"
, RegexOptions.Compiled
|
RegexOptions.Singleline);
public
static
string
CleanHtmlTags(
this
string
s,
string
exceptionPattern)
{
if
(
!
string
.IsNullOrEmpty(exceptionPattern))
return
new
Regex(
string
.Format(
"
<(?!{0})[^<>]*>
"
, exceptionPattern),
RegexOptions.Compiled
|
RegexOptions.Singleline).Replace(s,
""
);
return
tagRegex.Replace(s,
""
);
}
private
static
readonly
Regex spaceRegex
=
new
Regex(
@"
\s+
"
, RegexOptions.Compiled
|
RegexOptions.Singleline);
public
static
string
CleanWhitespace(
this
string
s)
{
return
spaceRegex.Replace(s,
"
"
);
}
public
static
string
IsRequired(
this
string
s)
{
if
(
string
.IsNullOrEmpty(s))
{
//
throw new ValidationException(string.Format("String is required: {0}", s));
throw
new
Exception(
string
.Format(
"
String is required: {0}
"
, s));
}
return
s;
}
private
static
readonly
Regex nonWordCharsRegex
=
new
Regex(
@"
[^\w]+
"
, RegexOptions.Compiled
|
RegexOptions.Singleline);
public
static
string
CleanCssClassName(
this
string
s)
{
return
nonWordCharsRegex.Replace(s,
"
_
"
).ToLower(System.Globalization.CultureInfo.CurrentCulture);
}
public
static
string
CleanText(
this
string
s)
{
if
(s
==
null
)
return
null
;
return
HttpUtility.HtmlEncode(s);
}
public
static
string
CleanHtml(
this
string
s)
{
//
AntiXss library from Microsoft
//
(
http://antixss.codeplex.com
)
string
encodedText
=
HttpUtility.HtmlEncode(s);
//
convert line breaks into an html break tag
return
encodedText.Replace(
"
"
,
"
<br />
"
);
}
public
static
string
CleanForQueryString(
this
string
s)
{
return
HttpUtility.UrlEncode(s);
}
public
static
string
CleanAttribute(
this
string
s)
{
return
HttpUtility.HtmlAttributeEncode(s);
}
//
todo: (nheskew) rename to something more generic (CleanAttributeALittle?) because not everything needs
//
the cleaning power of CleanAttribute (everything should but AntiXss.HtmlAttributeEncode encodes
//
*everyting* incl. white space :|) so attributes can get really long...but then my only current worry is around
//
the description meta tag. Attributes from untrusted sources *do* need the current CleanAttribute...
public
static
string
CleanHref(
this
string
s)
{
return
HttpUtility.HtmlAttributeEncode(s);
}
public
static
string
CleanCommentBody(
this
string
s)
{
return
s.CleanHtmlTags().CleanHtml().AutoAnchor();
}
private
static
readonly
Regex uriRegex
=
new
Regex(
"
(^|[^\\w'\
"
]
|
\\G)(
?<
uri
>
(
?
:https
?|
ftp)(
?
:
&
#
58
;
|
:)(
?
:
&
#
47
;
&
#
47
;
|
//
)(?:[^./\\s'\"<)\\]]+\\.)+[^./\\s'\"<)\\]]+(?:(?:/|/).*?)?)(?:[\\s\\.,\\)\\]'\"]?(?:\\s|\\.|\\)|\\]|,|<|$))", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public
static
string
AutoAnchor(
this
string
s)
{
MatchCollection uriMatches
=
uriRegex.Matches(s);
foreach
(Match uriMatch
in
uriMatches)
{
string
encodedUri
=
uriMatch.Groups[
"
uri
"
].Value;
if
(
!
string
.IsNullOrEmpty(encodedUri))
{
string
uri
=
HttpUtility.HtmlDecode(encodedUri);
s
=
s.Replace(encodedUri,
string
.Format(
"
<a href=\
"
{
0
}\
"
>{1}</a>
"
, uri.CleanHref(), uri.CleanText()));
}
}
return
s;
}
public
static
string
Shorten(
this
string
s,
int
characterCount)
{
string
text
=
!
string
.IsNullOrEmpty(s)
?
s.CleanHtmlTags().CleanWhitespace() :
""
;
if
(
!
string
.IsNullOrEmpty(text)
&&
characterCount
>
0
&&
text.Length
>
characterCount)
{
text
=
text.Substring(
0
, characterCount);
}
return
text;
}
public
static
string
Ellipsize(
this
string
s,
int
characterCount, Func
<
string
,
string
>
processStringPart)
{
return
s.Ellipsize(characterCount, processStringPart,
"
 …
"
);
}
public
static
string
Ellipsize(
this
string
s,
int
characterCount, Func
<
string
,
string
>
processStringPart,
string
ellipsis)
{
++
characterCount;
string
text
=
!
string
.IsNullOrEmpty(s)
?
s.CleanHtmlTags().CleanWhitespace() :
""
;
if
(
string
.IsNullOrEmpty(text)
||
characterCount
<
1
||
text.Length
<=
characterCount)
return
text;
string
[] words
=
text.Substring(
0
, characterCount).Split(
'
'
);
return
processStringPart(
string
.Join(
"
"
, words.Take(words.Length
-
1
).ToArray()))
+
ellipsis;
}
public
static
string
EllipsizeUri(
this
string
s,
int
characterCount, Func
<
string
,
string
>
processStringPart)
{
return
s.EllipsizeUri(characterCount, processStringPart,
"
 … 
"
);
}
//
info: (nheskew) ellipsis length hard-coded to the default decoded
public
static
string
EllipsizeUri(
this
string
s,
int
characterCount, Func
<
string
,
string
>
processStringPart,
string
ellipsis)
{
Uri uri;
int
ellipsisLength
=
3
;
//
not really accurate considering the use of the hellip character
//
return because we're not going to mess with the "URI" string
if
(
string
.IsNullOrEmpty(s)
||
characterCount
<
1
||
s.Length
<=
characterCount
||
!
Uri.TryCreate(s, UriKind.Absolute,
out
uri))
return
processStringPart(s);
string
start
=
uri.Scheme
+
"
://
"
;
string
end
=
uri.Segments.LastOrDefault()
??
""
;
if
(
!
string
.IsNullOrEmpty(uri.Query))
end
=
end
+
"
?
"
+
ellipsis;
//
need to ellipsize the host name because the string is already getting too long
if
(start.Length
+
uri.Host.Length
+
ellipsisLength
+
end.Length
>
characterCount)
{
string
host
=
uri.Host;
int
endLength
=
characterCount
-
(start.Length
+
host.Length
+
ellipsisLength);
if
(endLength
<
0
)
{
int
hostSubLength
=
(characterCount
-
(start.Length
+
ellipsisLength
*
2
))
/
2
;
//
two ellilpsis. host and end
host
=
hostSubLength
>
0
?
processStringPart(host.Substring(
0
, hostSubLength))
+
ellipsis
+
processStringPart(host.Substring(host.Length
-
hostSubLength, hostSubLength))
:
""
;
endLength
=
0
;
}
else
{
host
=
processStringPart(host);
}
return
processStringPart(start)
+
host
+
ellipsis
+
(endLength
>
0
?
processStringPart(end.Substring(end.Length
-
endLength, endLength)) :
""
);
}
start
=
start
+
uri.Host;
//
add as many path segments as we can
var pathParts
=
uri.Segments.Take(uri.Segments.Length
-
1
);
foreach
(
string
pathPart
in
pathParts)
{
if
(start.Length
+
pathPart.Length
+
ellipsisLength
+
end.Length
>
characterCount)
return
processStringPart(start)
+
ellipsis
+
processStringPart(end);
start
=
start
+
pathPart;
}
return
processStringPart(start
+
end);
}
public
static
string
ComputeHash(
this
string
value)
{
if
(
!
string
.IsNullOrEmpty(value))
{
MD5CryptoServiceProvider md5
=
new
MD5CryptoServiceProvider();
byte
[] data
=
Encoding.ASCII.GetBytes(value);
string
hash
=
""
;
data
=
md5.ComputeHash(data);
for
(
int
i
=
0
; i
<
data.Length; i
++
)
hash
+=
data[i].ToString(
"
x2
"
);
return
hash;
}
return
value;
}
public
static
bool
GuidTryParse(
this
string
s,
out
Guid result)
{
if
(s
==
null
)
{
throw
new
ArgumentNullException(
"
s
"
);
}
try
{
result
=
new
Guid(s);
return
true
;
}
catch
(FormatException)
{
result
=
Guid.Empty;
return
false
;
}
catch
(OverflowException)
{
result
=
Guid.Empty;
return
false
;
}
}
public
static
string
GetFileText(
this
string
virtualPath)
{
return
virtualPath.GetFileText(
new
HttpContextWrapper(HttpContext.Current));
}
public
static
string
GetFileText(
this
string
virtualPath, HttpContextBase httpContext)
{
string
path
=
httpContext.Server.MapPath(virtualPath);
if
(File.Exists(path))
return
File.ReadAllText(path);
return
null
;
}
public
static
string
Skip(
this
string
str,
char
word)
{
return
str.Replace(word,
'
'
);
}
}