У меня есть строка с 16 алфавитно-цифровыми символами, например, F4194E7CC775F003. Я хотел бы отформатировать его как F419-4E7C-C775-F003.
Я пытался использовать
string.Format("{0:####-####-####-####}","F4194E7CC775F003");
но это не работает, так как это не числовое значение.
Таким образом, я придумал следующее:
public class DashFormatter : IFormatProvider, ICustomFormatter
{
public object GetFormat(Type formatType)
{
return this;
}
public string Format(string format, object arg, IFormatProvider formatProvider)
{
char[] chars = arg.ToString().ToCharArray();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < chars.Length; i++)
{
if (i > 0 && i % 4 == 0)
{
sb.Append('-');
}
sb.Append(chars[i]);
}
return sb.ToString();
}
}
и при помощи
string.Format(new DashFormatter(), "{0}", "F4194E7CC775F003");
Я смог решить проблему, однако я надеялся, что существует лучший/более простой способ сделать это? Возможно, некоторое волшебство LINQ?
Спасибо.
Вы можете сделать это одной строкой без Linq:
StringBuilder splitMe = new StringBuilder("F4194E7CC775F003");
string joined = splitMe.Insert(12, "-").Insert(8, "-").Insert(4, "-").ToString();
char[] chars = "F4194E7CC775F003".ToCharArray();
var str = string.Format("{0}-{1}-{2}-{3}"
, new string(chars.Take(4).ToArray())
, new string(chars.Skip(4).Take(4).ToArray())
, new string(chars.Skip(8).Take(4).ToArray())
, new string(chars.Skip(12).Take(4).ToArray())
);
Вы можете сделать это с помощью регулярного выражения, хотя я не знаю, какова будет производительность этого метода по сравнению с другими методами.
string formattedString = Regex.Replace(yourString, "(\\S{4})\\B", "$1-");
Вы также можете поместить это в метод расширения для строки, если хотите:
yourString.ToDashedFormat();
Если вам нужен linq:
var formatted = string.Join("-", Enumerable.Range(0,4).Select(i=>s.Substring(i*4,4)).ToArray());
И если вам нужен эффективный:
var sb = new StringBuilder(19);
sb.Append(s,0,4);
for(var i = 1; i < 4; i++ )
{
sb.Append('-');
sb.Append(s,i*4, 4);
}
return sb.ToString();
Я не тестировал его, но я думаю, что он будет быстрее, чем StringBuilder.Insert, потому что он не перемещает остаток строки много раз, он просто записывает 4 символа. Также он не будет перераспределять базовую строку, потому что она предварительно распределена на 19 символов в начале.
Основываясь на ответе Карры, я сделал этот небольшой полезный метод:
private static string ToDelimitedString(string input, int position, string delimiter)
{
StringBuilder sb = new StringBuilder(input);
int x = input.Length / position;
while (--x > 0)
{
sb = sb.Insert(x * position, delimiter);
}
return sb.ToString();
}
Вы можете использовать его вот так:
string result = ToDelimitedString("F4194E7CC775F003", 4, "-");
И тестовый пример:
[Test]
public void ReturnsDelimitedString()
{
string input = "F4194E7CC775F003";
string actual = ToDelimitedString(input, 4, "-");
Assert.AreEqual("F419-4E7C-C775-F003", actual);
}
Самое простое решение, которое я могу придумать, это
var text = "F4194E7CC775F003";
var formattedText = string.Format(
"{0}-{1}-{2}-{3}",
text.Substring(0, 4),
text.Substring(4, 4),
text.Substring(8, 4),
text.Substring(12, 4));