Отделить целые числа от строки

Допустим, у меня есть веб-страница, которая в настоящее время принимает одно значение идентификатора через параметр url:
http://example.com/mypage.aspx?ID=1234

Я хочу изменить его, чтобы он принимал список идентификаторов, например:
http://example.com/mypage.aspx?IDs=1234,4321,6789

Так что он доступен для моего кода в виде строки через context.Request.QueryString ["IDs"]. Как лучше всего превратить это строковое значение в List ‹int>?

Изменить: Я знаю, как использовать .split () с запятой, чтобы получить список строк, но я спрашиваю, потому что не знаю, как легко преобразовать этот список строк в список int. Это все еще в .Net 2.0, поэтому никаких лямбд.


person Joel Coehoorn    schedule 15.09.2008    source источник


Ответы (13)


Не обижайтесь на тех, кто дал четкие ответы, но многие люди, кажется, отвечают на ваш вопрос, вместо того, чтобы решать вашу проблему. Вам нужно несколько идентификаторов, поэтому вы думаете, что можете это сделать:

http://example.com/mypage.aspx?IDs=1234,4321,6789

Проблема в том, что это ненадежное решение. Что делать в будущем, если вам нужно несколько значений, если в них есть запятые? Лучшее решение (и это совершенно справедливо для строки запроса) - использовать несколько параметров с одним и тем же именем:

http://example.com/mypage.aspx?ID=1234;ID=4321;ID=6789

Затем любой анализатор строки запроса, который вы используете, должен иметь возможность возвращать список идентификаторов. Если он не может справиться с этим (а также обрабатывает точки с запятой вместо амперсандов), значит, он сломан.

person Ovid    schedule 15.09.2008
comment
asp.net не имеет проблем с page.aspx? id = 1,2,3,4 & otherid = 4,5,6,7, поэтому я не понимаю, почему список, разделенный запятыми, не является надежным решением. - person Robert Paulson; 14.10.2008
comment
Поскольку, как указано, если значения могут содержать запятые, разделение на запятые проблематично. Протокол CGI позволяет использовать несколько параметров с одним и тем же именем, поэтому весь вопрос, могу ли я разделить их запятыми или нет, становится спорным. Вот для чего нужны повторяющиеся имена параметров. - person Ovid; 14.10.2008
comment
Я думаю, что если указаны буквенно-цифровые идентификаторы или идентификаторы GUID, запятая не будет отображаться внутри идентификаторов, и с этой точки зрения запятые являются надежным решением? Но я полагаю, что могут быть и другие проблемы, например Синтаксические синтаксические анализаторы вики, которые считают, что ссылки заканчиваются, когда есть запятая? - person KajMagnus; 16.04.2011
comment
это ужасная идея! а что если в будущем значения сохранятся;? ; не лучше, чем, - если вы хотите быть пунктуальным, оба запрещены RFC - person Nas Banov; 03.05.2011
comment
@Nas: извините, но это неверно. Точка с запятой (;) в строке, которая не предназначена для использования в качестве разделителя, НЕОБХОДИМА для экранирования uri (в данном случае% 3B), поскольку это зарезервированный символ. См. Раздел 2.2 RFC 2396 - ietf.org/rfc/rfc2396.txt. Любой синтаксический анализатор строки запроса, который не обрабатывает это, нарушается по определению. Вы правы в том, что ',' также является зарезервированным символом и его нужно экранировать, но вы не можете сказать, экранирован ли он для разделения или экранирован, потому что это допустимое значение. - person Ovid; 18.05.2011
comment
Это очень элегантное и информативное решение. Я не знал, что это можно сделать так. - person RichieACC; 15.06.2012

Что-то вроде этого может сработать:

public static IList<int> GetIdListFromString(string idList)
{
    string[] values = idList.Split(',');

    List<int> ids = new List<int>(values.Length);

    foreach (string s in values)
    {
        int i;

        if (int.TryParse(s, out i))
        {
            ids.Add(i);
        }
    }

    return ids;
}

Что затем будет использоваться:

string intString = "1234,4321,6789";

IList<int> list = GetIdListFromString(intString);

foreach (int i in list)
{
    Console.WriteLine(i);
}
person Compile This    schedule 15.09.2008
comment
Хорошо, я как раз собирался опубликовать тот же ответ :( - person Huppie; 15.09.2008

Вы можете создать экземпляр List ‹T› из массива.

VB.NET:

Dim lstIDs as new List(of Integer)(ids.split(','))

Это склонно к ошибкам приведения, хотя, если массив содержит элементы, отличные от int

person user7658    schedule 15.09.2008
comment
Проблема в том, что всего одна ошибка приведения приводит к уничтожению всего списка, но я все равно проголосовал за нее, и, возможно, мне следует придерживаться именно такого поведения. - person Joel Coehoorn; 15.09.2008

Все, что я могу придумать, - это перебрать список строк (который вы получили в результате выполнения разделения) и сделать что-то вроде int.TryParse() с ними одну за другой и поместить их в новый List<int>. Инкапсулируйте его где-нибудь в красивом маленьком вспомогательном методе, и это не будет слишком ужасно.

person Mark Embling    schedule 15.09.2008

Если вам нравится функциональный стиль, вы можете попробовать что-нибудь вроде

    string ids = "1,2,3,4,5";

    List<int> l = new List<int>(Array.ConvertAll(
        ids.Split(','), new Converter<string, int>(int.Parse)));

Никаких лямбда-выражений, но у вас есть преобразователи, предикаты и другие приятные вещи, которые можно сделать из методов.

person Jesse Millikan    schedule 15.09.2008

Я вижу, что мой ответ пришел довольно поздно, т.е. несколько других писали то же самое. Поэтому я представляю альтернативный метод, использующий регулярные выражения для проверки и разделения строки.

class Program
{
    //Accepts one or more groups of one or more digits, separated by commas.
    private static readonly Regex CSStringPattern = new Regex(@"^(\d+,?)*\d+$");

    //A single ID inside the string. Must only be used after validation
    private static readonly Regex SingleIdPattern = new Regex(@"\d+");

    static void Main(string[] args)
    {
        string queryString = "1234,4321,6789";

        int[] ids = ConvertCommaSeparatedStringToIntArray(queryString);
    }

    private static int[] ConvertCommaSeparatedStringToIntArray(string csString)
    {
        if (!CSStringPattern.IsMatch(csString))
            throw new FormatException(string.Format("Invalid comma separated string '{0}'",
                                                    csString));

        List<int> ids = new List<int>();
        foreach (Match match in SingleIdPattern.Matches(csString))
        {
            ids.Add(int.Parse(match.Value)); //No need to TryParse since string has been validated
        }
        return ids.ToArray();
    }
}
person Magnus Akselvoll    schedule 15.09.2008

Окончательный фрагмент кода, который, как я надеюсь, является лучшим из всех предложений:

Function GetIDs(ByVal IDList As String) As List(Of Integer)
    Dim SplitIDs() As String = IDList.Split(new Char() {","c}, StringSplitOptions.RemoveEmptyEntries)
    GetIDs = new List(Of Integer)(SplitIDs.Length)
    Dim CurID As Integer
    For Each id As String In SplitIDs
        If Integer.TryParse(id, CurID) Then GetIDs.Add(CurID)
    Next id
End Function

Я надеялся, что смогу сделать это одной или двумя строчками встроенного кода. Одна строка для создания массива строк и, надеюсь, найти что-то в структуре, о которой я еще не знал, чтобы обработать ее импорт в List ‹int>, которая могла бы разумно обрабатывать приведение. Но если мне нужно переместить это в метод, я это сделаю. И да, я использую VB. Я просто предпочитаю C # для того, чтобы задавать вопросы, потому что они привлекут более широкую аудиторию, а я примерно так же свободно говорю.

person Joel Coehoorn    schedule 15.09.2008

split - это первое, что приходит в голову, но оно возвращает массив, а не список; вы можете попробовать что-то вроде:


List<int> intList = new List<int>;

foreach (string tempString in ids.split(',')
{
    intList.add (convert.int32(tempString));
}

person RichieACC    schedule 15.09.2008

Вы можете использовать string.Split () для разделения значений после их извлечения из URL-адреса.

string[] splitIds = ids.split(',');
person Grokys    schedule 15.09.2008

Вам просто нужно будет пройти через них foreach и int.TryParse каждого из них. после этого просто добавьте в список.

Nevermind - @Splash опередил меня

person sirrocco    schedule 15.09.2008

List<int> convertIDs = new List<int>;
string[] splitIds = ids.split(',');
foreach(string s in splitIds)
{
    convertIDs.Add(int.Parse(s));
}

Для полноты вы захотите поместить try / catch вокруг цикла for (или вокруг вызова int.Parse ()) и обработать ошибку в соответствии с вашими требованиями. Вы также можете выполнить tryparse () следующим образом:

List<int> convertIDs = new List<int>;
string[] splitIds = ids.split(',');
foreach(string s in splitIds)
{
    int i;
    int.TryParse(out i);
    if (i != 0)
       convertIDs.Add(i);
}
person dpollock    schedule 15.09.2008

Чтобы продолжить предыдущий ответ, достаточно просто перебрать массив, возвращаемый Split, и преобразовать в новый массив целых чисел. Этот пример ниже на C #:

        string[] splitIds = stringIds.Split(',');

        int[] ids = new int[splitIds.Length];
        for (int i = 0; i < ids.Length; i++) {
            ids[i] = Int32.Parse(splitIds[i]);
        }
person Philibert Perusse    schedule 15.09.2008

Я думаю, что самый простой способ - разделить, как показано ранее, а затем перебрать значения и попытаться преобразовать их в int.

class Program
{
    static void Main(string[] args)
    {
        string queryString = "1234,4321,6789";

        int[] ids = ConvertCommaSeparatedStringToIntArray(queryString);
    }

    private static int[] ConvertCommaSeparatedStringToIntArray(string csString)
    {
        //splitting string to substrings
        string[] idStrings = csString.Split(',');

        //initializing int-array of same length
        int[] ids = new int[idStrings.Length];

        //looping all substrings
        for (int i = 0; i < idStrings.Length; i++)
        {
            string idString = idStrings[i];

            //trying to convert one substring to int
            int id;
            if (!int.TryParse(idString, out id))
                throw new FormatException(String.Format("Query string contained malformed id '{0}'", idString));

            //writing value back to the int-array
            ids[i] = id;
        }

        return ids;
    }
}
person Magnus Akselvoll    schedule 15.09.2008