C # IsBetween String Logic - PullRequest
       3

C # IsBetween String Logic

2 голосов
/ 29 декабря 2011

В поисках решения, некоторых идей или в правильном направлении решения проблемы.

По сути, я должен выяснить, находится ли строковое значение между строковым значением Low и High. Однако значения имеют формат, который String.Compare не будет работать. Но человек может легко понять.

Например, один из моих диапазонов - низкий: A7, высокий A12. A8 подходит между этими значениями, но String.Compare говорит, что это не так. A13 не будет соответствовать между значениями.

Другие примеры значений Low и High:

Низкое значение - Высокое значение

1A1 - 1A12

25W00 - 25W050

42W1 - 42W296

W232N0002 - W232N000598

В приведенных выше примерах 1A2 подходил бы между значениями Low High (1A1 и 1A12), но 1A100 - нет.

Есть идеи, как решить эту проблему? Я знаю, что с этим уже сталкивались раньше.

Ответы [ 3 ]

3 голосов
/ 29 декабря 2011

Это может использовать некоторую оптимизацию, но это подтверждение концепции.Просто преобразуйте буквы в числовые значения и сравните результаты:

private bool ValueIsBetween(string value, string lowValue, string highValue)
{
    long low = long.Parse(ConvertToNumber(lowValue));
    long high = long.Parse(ConvertToNumber(highValue));
    long val = long.Parse(ConvertToNumber(value));
    return val > low && val < high;
}

private string ConvertToNumber(string value)
{
    value = value.ToUpper();
    value = value.Replace("A", "0");
    value = value.Replace("B", "1");
    value = value.Replace("C", "2");
    value = value.Replace("D", "3");
    value = value.Replace("E", "4");
    value = value.Replace("F", "5");
    value = value.Replace("G", "6");
    value = value.Replace("H", "7");
    value = value.Replace("I", "8");
    value = value.Replace("J", "9");
    value = value.Replace("K", "10");
    value = value.Replace("L", "11");
    value = value.Replace("M", "12");
    value = value.Replace("N", "13");
    value = value.Replace("O", "14");
    value = value.Replace("P", "15");
    value = value.Replace("Q", "16");
    value = value.Replace("R", "17");
    value = value.Replace("S", "18");
    value = value.Replace("T", "19");
    value = value.Replace("U", "20");
    value = value.Replace("V", "21");
    value = value.Replace("W", "22");
    value = value.Replace("X", "23");
    value = value.Replace("Y", "24");
    value = value.Replace("Z", "25");

    return value;
}

Результаты:

ValueIsBetween("1A2", "1A1", "1A12");

true

ValueIsBetween("1A100", "1A1", "1A12");

false

ValueIsBetween("43W4", "42W1", "44W3");

true

Редактировать: Попробуйте вместо этого этот улучшенный алгоритм:

private bool ValueIsBetween(string value, string lowValue, string highValue)
{
    return !ValueIsLessThan(value, lowValue) && ValueIsLessThan(value, highValue);
}

private bool ValueIsLessThan(string value, string compareTo)
{
    var matches = Regex.Matches(value, "[0-9]+|[a-zA-Z]+");
    var matchesB = Regex.Matches(compareTo, "[0-9]+|[a-zA-Z]+");

    var count = matches.Count < matchesB.Count ? matches.Count : matchesB.Count;

    for (int i = 0; i < count; i++)
    {
        long val;
        long val2;
        if (long.TryParse(matches[i].Value, out val))
        {
            if (long.TryParse(matchesB[i].Value, out val2))
            {
                if (val > val2) return false;
                if (val < val2) return true;
            }
            else
            {
                return false;
            }
        }
        else
        {
            if (matches[i].Value.CompareTo(matchesB[i].Value) > 0 ) return false;
            if (matches[i].Value.CompareTo(matchesB[i].Value) < 0 ) return true;
        }
    }

    return true;
}

Результаты:

ValueIsBetween("B431Z543", "A0", "Z9");

true

ValueIsBetween("4B31Z543", "A0", "Z9");

false

ValueIsBetween("1A2", "1A1", "1A12");

true

ValueIsBetween("1A100", "1A1", "1A12");

false

ValueIsBetween("43W4", "42W1", "44W3");

true

ValueIsBetween("W5", "CC4", "CC6");

false

ValueIsBetween("W8B4", "W5C3", "W7C3");

false

ValueIsBetween("W5C4", "W5C3", "C7W3"); 

false

0 голосов
/ 29 декабря 2011

Предполагая, что нечисловые части являются фиксированными (т. Е. Вы не ищете 1B1 между 1A1 и 1C1 ), вы можете использовать регулярное выражениечтобы расширить числовые значения до определенной фиксированной ширины, чтобы вы могли затем сравнить строки.

Например, используя

static Regex digits = new Regex(@"\d+");

static string ExpandDigits(string s)
{
    return digits.Replace(s, m => string.Format("{0:D10}", int.Parse(m.ToString())));
}

, затем вызывая ExpandDigits("W232N0002"), вы получите W0000000232N0000000002.

Вы можете использовать метод сравнения, подобный этому:

static bool IsInRange(string lower, string upper, string test)
{
    test = ExpandDigits(test);
    lower = ExpandDigits(lower);

    if (lower.CompareTo(test) <= 0)
    {
        upper = ExpandDigits(upper);
        if (test.CompareTo(upper) <= 0)
        {
            return true;
        }
    }

    return false;
}
0 голосов
/ 29 декабря 2011

Создание класса, возможно абстрактного, с подклассами для каждого шаблона.

Шаблон для "25W00" может быть ^(?<LEFTTHING>.{2})(?<MIDDLETHING>.{1})(?<RIGHTTHING>.{2})$

В вашем классе запишите каждую группу регулярных выражений в виде строки или числа в зависимости от ситуации.

Полагаю, вы могли бы придумать некоторые соглашения, чтобы вы могли иметь даже один тип - и передать этот шаблон конструктору.

У вас может даже быть какой-то действительно умный класс, в котором вы передаете две строки и общий шаблон. Этот суперкласс строит соответствующие «сопоставимые» классы (как указано выше) и возвращает логический результат сравнения. В этом случае ваш код клиента будет очень чистым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...