PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/Xtensive.Core/Xtensive.Core/System/StringExtensions.cs

https://code.google.com/p/dataobjectsdotnet/
C# | 396 lines | 216 code | 25 blank | 155 comment | 52 complexity | 3741f334de4220d4bc05abadb834c9bd MD5 | raw file
Possible License(s): AGPL-3.0
  1. // Copyright (C) 2003-2010 Xtensive LLC.
  2. // All rights reserved.
  3. // For conditions of distribution and use, see license.
  4. // Created by: Dmitri Maximov
  5. // Created: 2008.07.18
  6. using System.Collections.Generic;
  7. using System.Text;
  8. using System.Text.RegularExpressions;
  9. using System.Web.UI;
  10. using Xtensive.Core;
  11. using Xtensive.Core.Resources;
  12. namespace System
  13. {
  14. /// <summary>
  15. /// <see cref="string"/> related extension methods.
  16. /// </summary>
  17. public static class StringExtensions
  18. {
  19. private const string ThisMemberName = "this";
  20. private static readonly Regex formatWithRegex = new Regex(
  21. @"\{\{|\{([\w\.\[\]]+)((?:[,:][^}]+)?\})",
  22. RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
  23. /// <summary>
  24. /// Formats the specified <paramref name="format"/> string using <see cref="string.Format(string,object[])" method/>.
  25. /// </summary>
  26. /// <param name="format">The format string.</param>
  27. /// <param name="formatProvider">The format provider.</param>
  28. /// <param name="arguments">The arguments.</param>
  29. /// <returns>Formatted string.</returns>
  30. public static string FormatWith(this string format, IFormatProvider formatProvider, params object[] arguments)
  31. {
  32. ArgumentValidator.EnsureArgumentNotNull(format, "format");
  33. ArgumentValidator.EnsureArgumentNotNull(formatProvider, "formatProvider");
  34. return string.Format(formatProvider, format, arguments);
  35. }
  36. /// <summary>
  37. /// Formats the specified <paramref name="format"/> string using <see cref="string.Format(string,object[])" method/>.
  38. /// </summary>
  39. /// <param name="format">The format string.</param>
  40. /// <param name="arguments">The arguments.</param>
  41. /// <returns>Formatted string.</returns>
  42. public static string FormatWith(this string format, params object[] arguments)
  43. {
  44. ArgumentValidator.EnsureArgumentNotNull(format, "format");
  45. return string.Format(format, arguments);
  46. }
  47. /// <summary>
  48. /// Formats the specified <paramref name="format"/> string using <see cref="string.Format(string,object)" method/>.
  49. /// </summary>
  50. /// <param name="format">The format string.</param>
  51. /// <param name="arg0">The first argument.</param>
  52. /// <returns>Formatted string.</returns>
  53. public static string FormatWith(this string format, object arg0)
  54. {
  55. ArgumentValidator.EnsureArgumentNotNull(format, "format");
  56. var arguments = new List<object>();
  57. string rewrittenFormat = formatWithRegex.Replace(format, m => {
  58. string propertyName = m.Groups[1].Value.Trim();
  59. if (propertyName.Length==0)
  60. return m.Value;
  61. arguments.Add((propertyName=="0" || propertyName==ThisMemberName) ? arg0 : DataBinder.Eval(arg0, propertyName));
  62. return "{" + (arguments.Count - 1) + m.Groups[2].Value;
  63. });
  64. return string.Format(rewrittenFormat, arguments.ToArray());
  65. }
  66. /// <summary>
  67. /// Formats the specified <paramref name="format"/> string using <see cref="string.Format(string,object,object)" method/>.
  68. /// </summary>
  69. /// <param name="format">The format string.</param>
  70. /// <param name="arg0">The first argument.</param>
  71. /// <param name="arg1">The second argument.</param>
  72. /// <returns>Formatted string.</returns>
  73. public static string FormatWith(this string format, object arg0, object arg1)
  74. {
  75. ArgumentValidator.EnsureArgumentNotNull(format, "format");
  76. return string.Format(format, arg0, arg1);
  77. }
  78. /// <summary>
  79. /// Formats the specified <paramref name="format"/> string using <see cref="string.Format(string,object,object,object)" method/>.
  80. /// </summary>
  81. /// <param name="format">The format string.</param>
  82. /// <param name="arg0">The first argument.</param>
  83. /// <param name="arg1">The second argument.</param>
  84. /// <param name="arg2">The third argument.</param>
  85. /// <returns>Formatted string.</returns>
  86. public static string FormatWith(this string format, object arg0, object arg1, object arg2)
  87. {
  88. ArgumentValidator.EnsureArgumentNotNull(format, "format");
  89. return string.Format(format, arg0, arg1, arg2);
  90. }
  91. /// <summary>
  92. /// Cuts the specified <paramref name="suffix"/> from <paramref name="value"/>.
  93. /// </summary>
  94. /// <param name="value">The original string value.</param>
  95. /// <param name="suffix">The suffix to cut.</param>
  96. /// <returns>String without <paramref name="suffix"/> if it was found;
  97. /// otherwise, original <paramref name="value"/>.</returns>
  98. public static string TryCutSuffix(this string value, string suffix)
  99. {
  100. if (!value.EndsWith(suffix))
  101. return value;
  102. return value.Substring(0, value.Length - suffix.Length);
  103. }
  104. /// <summary>
  105. /// Cuts the specified <paramref name="suffix"/> from <paramref name="value"/>.
  106. /// </summary>
  107. /// <param name="value">The original string value.</param>
  108. /// <param name="suffix">The suffix to cut.</param>
  109. /// <param name="isCut">Upon return contains <see langword="true"/>
  110. /// if suffix was cut, otherwise <see langword="false"/></param>
  111. /// <returns>String without <paramref name="suffix"/> if it was found;
  112. /// otherwise, original <paramref name="value"/>.</returns>
  113. public static string TryCutSuffix(this string value, string suffix, out bool isCut)
  114. {
  115. if (!value.EndsWith(suffix)) {
  116. isCut = false;
  117. return value;
  118. }
  119. isCut = true;
  120. return value.Substring(0, value.Length - suffix.Length);
  121. }
  122. /// <summary>
  123. /// Cuts the specified <paramref name="prefix"/> from <paramref name="value"/>.
  124. /// </summary>
  125. /// <param name="value">The original string value.</param>
  126. /// <param name="prefix">The prefix to cut.</param>
  127. /// <returns>String without <paramref name="prefix"/> if it was found;
  128. /// otherwise, original <paramref name="value"/>.</returns>
  129. public static string TryCutPrefix(this string value, string prefix)
  130. {
  131. if (!value.StartsWith(prefix))
  132. return value;
  133. return value.Substring(prefix.Length);
  134. }
  135. /// <summary>
  136. /// Cuts the specified <paramref name="prefix"/> from <paramref name="value"/>.
  137. /// </summary>
  138. /// <param name="value">The original string value.</param>
  139. /// <param name="prefix">The prefix to cut.</param>
  140. /// <param name="isCut">Upon return contains <see langword="true"/>
  141. /// if prefix was cut, otherwise <see langword="false"/></param>
  142. /// <returns>String without <paramref name="prefix"/> if it was found;
  143. /// otherwise, original <paramref name="value"/>.</returns>
  144. public static string TryCutPrefix(this string value, string prefix, out bool isCut)
  145. {
  146. if (!value.StartsWith(prefix)) {
  147. isCut = false;
  148. return value;
  149. }
  150. isCut = true;
  151. return value.Substring(prefix.Length);
  152. }
  153. /// <summary>
  154. /// Indents the specified string value.
  155. /// </summary>
  156. /// <param name="value">The value to indent.</param>
  157. /// <param name="indentSize">Size of the indent (in space characters).</param>
  158. /// <returns>Indented <paramref name="value"/>.</returns>
  159. public static string Indent(this string value, int indentSize)
  160. {
  161. return value.Indent(indentSize, true);
  162. }
  163. /// <summary>
  164. /// Indents the specified string value.
  165. /// </summary>
  166. /// <param name="value">The value to indent.</param>
  167. /// <param name="indentSize">Size of the indent (in space characters).</param>
  168. /// <param name="indentFirstLine">If set to <see langword="true"/>, first line must be indented;
  169. /// otherwise, <see langword="false"/>.</param>
  170. /// <returns>Indented <paramref name="value"/>.</returns>
  171. public static string Indent(this string value, int indentSize, bool indentFirstLine)
  172. {
  173. ArgumentValidator.EnsureArgumentNotNull(value, "value");
  174. var indent = new string(' ', indentSize);
  175. var sb = new StringBuilder();
  176. if (indentFirstLine)
  177. sb.Append(indent);
  178. int start = 0;
  179. int next;
  180. while ((next = value.IndexOf('\n', start)) >= 0) {
  181. next++;
  182. sb.Append(value.Substring(start, next - start));
  183. sb.Append(indent);
  184. start = next;
  185. }
  186. sb.Append(value.Substring(start, value.Length - start));
  187. return sb.ToString();
  188. }
  189. /// <summary>
  190. /// Determines whether <paramref name="x"/> <see cref="string"/> is less than <paramref name="y"/> <see cref="string"/>.
  191. /// </summary>
  192. /// <param name="x">The first argument.</param>
  193. /// <param name="y">The second argument.</param>
  194. /// <returns>
  195. /// <see langword="true" /> if <paramref name="x"/> is less than <paramref name="y"/>; otherwise <see langword="false" />.
  196. /// </returns>
  197. public static bool LessThan(this string x, string y)
  198. {
  199. if (x == y)
  200. return false;
  201. if (x == null)
  202. return true;
  203. if (y == null)
  204. return false;
  205. return x.CompareTo(y) < 0;
  206. }
  207. /// <summary>
  208. /// Determines whether <paramref name="x"/> <see cref="string"/> is less than or equals to <paramref name="y"/> <see cref="string"/>.
  209. /// </summary>
  210. /// <param name="x">The first argument.</param>
  211. /// <param name="y">The second argument.</param>
  212. /// <returns>
  213. /// <see langword="true" /> if <paramref name="x"/> is less than or equals to <paramref name="y"/>; otherwise <see langword="false" />.
  214. /// </returns>
  215. public static bool LessThanOrEqual(this string x, string y)
  216. {
  217. if (x == y)
  218. return true;
  219. if (x == null)
  220. return true;
  221. if (y == null)
  222. return false;
  223. return x.CompareTo(y) <= 0;
  224. }
  225. /// <summary>
  226. /// Determines whether <paramref name="x"/> <see cref="string"/> is greater than <paramref name="y"/> <see cref="string"/>.
  227. /// </summary>
  228. /// <param name="x">The first argument.</param>
  229. /// <param name="y">The second argument.</param>
  230. /// <returns>
  231. /// <see langword="true" /> if <paramref name="x"/> is greater than <paramref name="y"/>; otherwise <see langword="false" />.
  232. /// </returns>
  233. public static bool GreaterThan(this string x, string y)
  234. {
  235. if (x == y)
  236. return false;
  237. if (x == null)
  238. return false;
  239. if (y == null)
  240. return true;
  241. return x.CompareTo(y) > 0;
  242. }
  243. /// <summary>
  244. /// Determines whether <paramref name="x"/> <see cref="string"/> is less than <paramref name="y"/> <see cref="string"/>.
  245. /// </summary>
  246. /// <param name="x">The first argument.</param>
  247. /// <param name="y">The second argument.</param>
  248. /// <returns>
  249. /// <see langword="true" /> if <paramref name="x"/> is less than <paramref name="y"/>; otherwise <see langword="false" />.
  250. /// </returns>
  251. public static bool GreaterThanOrEqual(this string x, string y)
  252. {
  253. if (x == y)
  254. return true;
  255. if (x == null)
  256. return false;
  257. if (y == null)
  258. return true;
  259. return x.CompareTo(y) >= 0;
  260. }
  261. /// <summary>
  262. /// Converts the <paramref name="source"/> to a separated string
  263. /// using "escape separator" syntax to encode inner separators in
  264. /// <paramref name="source"/> parts.
  265. /// </summary>
  266. /// <param name="source">The sequence of strings to join.</param>
  267. /// <param name="escape">The escape character.</param>
  268. /// <param name="delimiter">The delimiter character.</param>
  269. /// <returns>
  270. /// Comma-separated string of all the items
  271. /// from <paramref name="source"/>.
  272. /// </returns>
  273. /// <exception cref="ArgumentException"><paramref name="escape"/>==<paramref name="delimiter"/>.</exception>
  274. public static string RevertibleJoin(this IEnumerable<string> source, char escape, char delimiter)
  275. {
  276. ArgumentValidator.EnsureArgumentNotNull(source, "source");
  277. if (escape==delimiter)
  278. throw new ArgumentException(
  279. Strings.ExEscapeCharacterMustDifferFromDelimiterCharacter);
  280. var sb = new StringBuilder();
  281. bool needDelimiter = false;
  282. foreach (var part in source) {
  283. if (needDelimiter)
  284. sb.Append(delimiter);
  285. else
  286. needDelimiter = true;
  287. if (part==null)
  288. continue;
  289. for (int i = 0; i<part.Length; i++) {
  290. char c = part[i];
  291. if (c==delimiter || c==escape)
  292. sb.Append(escape);
  293. sb.Append(c);
  294. }
  295. }
  296. return sb.ToString();
  297. }
  298. /// <summary>
  299. /// Reverts the result of <see cref="RevertibleJoin"/>.
  300. /// </summary>
  301. /// <param name="source">The source string to split.</param>
  302. /// <param name="escape">The escape character.</param>
  303. /// <param name="delimiter">The delimiter character.</param>
  304. /// <returns>
  305. /// The array of values that were previously joined
  306. /// by <see cref="RevertibleJoin"/>.
  307. /// </returns>
  308. /// <exception cref="ArgumentException"><paramref name="escape"/>==<paramref name="delimiter"/>.</exception>
  309. public static IEnumerable<string> RevertibleSplit(this string source, char escape, char delimiter)
  310. {
  311. ArgumentValidator.EnsureArgumentNotNull(source, "source");
  312. if (escape==delimiter)
  313. throw new ArgumentException(
  314. Strings.ExEscapeCharacterMustDifferFromDelimiterCharacter);
  315. var sb = new StringBuilder();
  316. bool previousCharIsEscape = false;
  317. for (int i = 0; i<source.Length; i++) {
  318. char c = source[i];
  319. if (previousCharIsEscape) {
  320. sb.Append(c);
  321. previousCharIsEscape = false;
  322. }
  323. else if (c==escape) {
  324. previousCharIsEscape = true;
  325. }
  326. else if (c==delimiter) {
  327. yield return sb.ToString();
  328. sb.Length = 0;
  329. }
  330. else
  331. sb.Append(c);
  332. }
  333. yield return sb.ToString();
  334. }
  335. /// <summary>
  336. /// Reverts the result of <see cref="RevertibleJoin"/>.
  337. /// </summary>
  338. /// <param name="source">The source string to split.</param>
  339. /// <param name="escape">The escape character.</param>
  340. /// <param name="delimiter">The delimiter character.</param>
  341. /// <returns>
  342. /// The array of values that were previously joined
  343. /// by <see cref="RevertibleJoin"/>.
  344. /// </returns>
  345. /// <exception cref="ArgumentException"><paramref name="escape"/>==<paramref name="delimiter"/>.</exception>
  346. public static Pair<string> RevertibleSplitFirstAndTail(this string source, char escape, char delimiter)
  347. {
  348. ArgumentValidator.EnsureArgumentNotNull(source, "source");
  349. if (escape==delimiter)
  350. throw new ArgumentException(
  351. Strings.ExEscapeCharacterMustDifferFromDelimiterCharacter);
  352. var sb = new StringBuilder();
  353. bool previousCharIsEscape = false;
  354. for (int i = 0; i<source.Length; i++) {
  355. char c = source[i];
  356. if (previousCharIsEscape) {
  357. sb.Append(c);
  358. previousCharIsEscape = false;
  359. }
  360. else if (c==escape) {
  361. previousCharIsEscape = true;
  362. }
  363. else if (c==delimiter)
  364. return new Pair<string>(sb.ToString(), source.Substring(i + 1));
  365. else
  366. sb.Append(c);
  367. }
  368. return new Pair<string>(sb.ToString(), null);
  369. }
  370. }
  371. }