csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
205 lines
5.5 KiB
205 lines
5.5 KiB
using System;
|
|
using System.Globalization;
|
|
using static System.Char;
|
|
|
|
namespace Avalonia.Utilities
|
|
{
|
|
public struct StringTokenizer : IDisposable
|
|
{
|
|
private const char DefaultSeparatorChar = ',';
|
|
|
|
private readonly string _s;
|
|
private readonly int _length;
|
|
private readonly char _separator;
|
|
private readonly string _exceptionMessage;
|
|
private readonly IFormatProvider _formatProvider;
|
|
private int _index;
|
|
private int _tokenIndex;
|
|
private int _tokenLength;
|
|
|
|
public StringTokenizer(string s, IFormatProvider formatProvider, string exceptionMessage = null)
|
|
: this(s, GetSeparatorFromFormatProvider(formatProvider), exceptionMessage)
|
|
{
|
|
_formatProvider = formatProvider;
|
|
}
|
|
|
|
public StringTokenizer(string s, char separator = DefaultSeparatorChar, string exceptionMessage = null)
|
|
{
|
|
_s = s ?? throw new ArgumentNullException(nameof(s));
|
|
_length = s?.Length ?? 0;
|
|
_separator = separator;
|
|
_exceptionMessage = exceptionMessage;
|
|
_formatProvider = CultureInfo.InvariantCulture;
|
|
_index = 0;
|
|
_tokenIndex = -1;
|
|
_tokenLength = 0;
|
|
|
|
while (_index < _length && IsWhiteSpace(_s, _index))
|
|
{
|
|
_index++;
|
|
}
|
|
}
|
|
|
|
public string CurrentToken => _tokenIndex < 0 ? null : _s.Substring(_tokenIndex, _tokenLength);
|
|
|
|
public void Dispose()
|
|
{
|
|
if (_index != _length)
|
|
{
|
|
throw GetFormatException();
|
|
}
|
|
}
|
|
|
|
public bool TryReadInt32(out Int32 result, char? separator = null)
|
|
{
|
|
var success = TryReadString(out var stringResult, separator);
|
|
result = success ? int.Parse(stringResult, _formatProvider) : 0;
|
|
return success;
|
|
}
|
|
|
|
public int ReadInt32(char? separator = null)
|
|
{
|
|
if (!TryReadInt32(out var result, separator))
|
|
{
|
|
throw GetFormatException();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public bool TryReadDouble(out double result, char? separator = null)
|
|
{
|
|
var success = TryReadString(out var stringResult, separator);
|
|
result = success ? double.Parse(stringResult, _formatProvider) : 0;
|
|
return success;
|
|
}
|
|
|
|
public double ReadDouble(char? separator = null)
|
|
{
|
|
if (!TryReadDouble(out var result, separator))
|
|
{
|
|
throw GetFormatException();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public bool TryReadString(out string result, char? separator = null)
|
|
{
|
|
var success = TryReadToken(separator ?? _separator);
|
|
result = CurrentToken;
|
|
return success;
|
|
}
|
|
|
|
public string ReadString(char? separator = null)
|
|
{
|
|
if (!TryReadString(out var result, separator))
|
|
{
|
|
throw GetFormatException();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private bool TryReadToken(char separator)
|
|
{
|
|
_tokenIndex = -1;
|
|
|
|
if (_index >= _length)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var c = _s[_index];
|
|
|
|
var index = _index;
|
|
var length = 0;
|
|
|
|
while (_index < _length)
|
|
{
|
|
c = _s[_index];
|
|
|
|
if (IsWhiteSpace(c) || c == separator)
|
|
{
|
|
break;
|
|
}
|
|
|
|
_index++;
|
|
length++;
|
|
}
|
|
|
|
SkipToNextToken(separator);
|
|
|
|
_tokenIndex = index;
|
|
_tokenLength = length;
|
|
|
|
if (_tokenLength < 1)
|
|
{
|
|
throw GetFormatException();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void SkipToNextToken(char separator)
|
|
{
|
|
if (_index < _length)
|
|
{
|
|
var c = _s[_index];
|
|
|
|
if (c != separator && !IsWhiteSpace(c))
|
|
{
|
|
throw GetFormatException();
|
|
}
|
|
|
|
var length = 0;
|
|
|
|
while (_index < _length)
|
|
{
|
|
c = _s[_index];
|
|
|
|
if (c == separator)
|
|
{
|
|
length++;
|
|
_index++;
|
|
|
|
if (length > 1)
|
|
{
|
|
throw GetFormatException();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!IsWhiteSpace(c))
|
|
{
|
|
break;
|
|
}
|
|
|
|
_index++;
|
|
}
|
|
}
|
|
|
|
if (length > 0 && _index >= _length)
|
|
{
|
|
throw GetFormatException();
|
|
}
|
|
}
|
|
}
|
|
|
|
private FormatException GetFormatException() =>
|
|
_exceptionMessage != null ? new FormatException(_exceptionMessage) : new FormatException();
|
|
|
|
private static char GetSeparatorFromFormatProvider(IFormatProvider provider)
|
|
{
|
|
var c = DefaultSeparatorChar;
|
|
|
|
var formatInfo = NumberFormatInfo.GetInstance(provider);
|
|
if (formatInfo.NumberDecimalSeparator.Length > 0 && c == formatInfo.NumberDecimalSeparator[0])
|
|
{
|
|
c = ';';
|
|
}
|
|
|
|
return c;
|
|
}
|
|
}
|
|
}
|