Ищем C#-эквивалент scanf

Раньше я программировал на языке C и нашел функцию scanf очень полезной. К сожалению, в C# нет эквивалента.

Я использую его для анализа полуструктурированных текстовых файлов.

Я нашел интересный пример реализации scanf здесь. К сожалению, он выглядит старым и неполным.

Кто-нибудь знает реализацию scanf С#? Или хотя бы что-то, что работало бы как перевернутое string.Format?


person Larry    schedule 23.01.2009    source источник


Ответы (9)


Если регулярные выражения у вас не работают, я только что опубликовал замену sscanf() для .NET. Код можно просмотреть и загрузить по адресу http://www.blackbeltcoder.com/Articles/strings/a-sscanf-replacement-for-net.

person Jonathan Wood    schedule 25.02.2011
comment
Это злой хак имхо, вам лучше использовать сопоставление групп регулярных выражений. Это .net-эквивалент sscanf и даже лучше. Смотрите сообщение ниже. - person jurik; 18.06.2014
comment
@jurik: Я полагаю, было бы чересчур просить вас подтвердить ваше заявление? Regex великолепен, и вы можете использовать его, если хотите. Но как можно реализовать scanf на C#? Это просто критика того, что вам не нравится. Это не делает его взломом. Ради бога, проявите немного терпимости к людям, которые могут решить сделать что-то не так, как вам нравится. - person Jonathan Wood; 18.06.2014
comment
ладно, возможно, я немного погорячился без достойных доказательств, но позвольте мне попытаться объяснить. Я нашел эту ветку некоторое время назад, и после просмотра кода я не хотел использовать ее в производстве. Почему-то казалось, что если бы платформа .net захотела использовать scanf, она бы его включила. Поэтому я посмотрел дальше и нашел нужный мне пример. Это та же самая функциональность, что и у sscanf, но без специального кода. Я не хотел обидеть вас или ваше решение, извините. Я вообще очень люблю хаки. Когда-нибудь это необходимо. - person jurik; 19.06.2014
comment
@jurik: RegEx делает гораздо больше, поэтому я, безусловно, могу понять людей, предпочитающих его. Основная причина, по которой я написал scanf для C#, заключалась в том, чтобы облегчить разработчикам перенос кода C и людям, знакомым с синтаксисом scanf, но не знакомым с регулярными выражениями. - person Jonathan Wood; 19.06.2014
comment
@jonahthan, в таком случае. Хороший! портировать намного проще, если охвачены хотя бы основы. - person jurik; 20.06.2014

Поскольку файлы «полуструктурированы», нельзя ли использовать комбинацию методов ReadLine() и TryParse() или класс Regex для анализа ваших данных?

person Mitch Wheat    schedule 23.01.2009
comment
Конечно, я мог бы :) Однако scanf настолько удобен и удобен по сравнению с регулярным выражением. Я почти уверен, что это стоит усилий. - person Larry; 23.01.2009
comment
Регулярные выражения не так уж и плохи. Загрузите один из бесплатных инструментов (например, Expresso), и регулярные выражения намного проще создавать и использовать. - person Mitch Wheat; 23.01.2009
comment
Лично я ненавижу scanf(): регулярные выражения дают вам гораздо больше контроля и гибкости, стоит изучить хотя бы основы. Я изучил регулярные выражения, когда программировал на Perl, и они мне понравились, поэтому я был вне себя от радости, обнаружив регулярные выражения в .NET. - person AAT; 11.09.2009
comment
В настоящее время я использую SScanf() с открытым исходным кодом по этой ссылке... попробуйте blackbeltcoder.com/Articles/strings/ - person Dhanasekar; 31.10.2012
comment
Забавно, что здесь никто не ставит под сомнение производительность regex против scanf. - person Ray; 09.02.2015

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

person okutane    schedule 23.01.2009
comment
Ой, я понятия не имею, как напрямую использовать библиотеки времени выполнения C. Я бы предпочел избежать этого и вместо этого придерживаться регулярных выражений. - person Larry; 23.01.2009

Я нашел лучшее решение, чем использовать sscanf из C или какую-то переписанную кем-то часть (без обид)

http://msdn.microsoft.com/en-us/library/63ew9az0.aspx взгляните на эту статью, в ней объясняется, как создавать именованные группы для извлечения нужных данных из шаблонной строки. Остерегайтесь маленькой ошибки в статье и лучшей версии ниже. (двоеточие не было частью группы)

using System;
using System.Text.RegularExpressions;

public class Example
{
   public static void Main()
   {
      string url = "http://www.contoso.com:8080/letters/readme.html";
      Regex r = new Regex(@"^(?<proto>\w+)://[^/]+?(?<port>:\d+)?/",RegexOptions.None, TimeSpan.FromMilliseconds(150));
      Match m = r.Match(url);
      if (m.Success)
         Console.WriteLine(r.Match(url).Result("${proto}:${port}")); 
   }
}
// The example displays the following output: 
//       http::8080
person jurik    schedule 07.08.2013
comment
Стоит отметить, что этот пример на самом деле не дает ожидаемого результата. Это приводит к http::8080, когда я его тестирую. - person Khale_Kitha; 07.03.2016
comment
Вы абсолютно правы, но это не имеет смысла. Двоеточие находится за пределами совпадающей группы, поэтому его не следует учитывать. Я предположил, что proto был http, а порт был 8080 без двоеточий. Вот почему я отредактировал исходный пример. - person jurik; 03.04.2017

Попробуйте импортировать msvcrt.dll

using System.Runtime.InteropServices;

namespace Sample
{
    class Program
    {
        [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int printf(string format, __arglist);

        [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int scanf(string format, __arglist);

        static void Main()
        {
            int a, b;
            scanf("%d%d", __arglist(out a, out b));
            printf("The sum of %d and %d is %d.\n", __arglist(a, b, a + b));
        }
    }
}

который хорошо работает на .NET Framework. Но в Mono он показывает сообщение об ошибке:

Unhandled Exception:
System.InvalidProgramException: Invalid IL code in Sample.Program:Main (): IL_0009: call      0x0a000001


[ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidProgramException: Invalid IL code in Sample.Program:Main (): IL_0009: call      0x0a000001

Если вам нужна совместимость с Mono, вам нужно избегать использования arglist

using System.Runtime.InteropServices;

namespace Sample
{
    class Program
    {
        [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int printf(string format, int a, int b, int c);

        [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int scanf(string format, out int a, out int b);

        static void Main()
        {
            int a, b;
            scanf("%d%d", out a, out b);
            printf("The sum of %d and %d is %d.\n", a, b, a + b);
        }
    }
}

в котором количество аргументов фиксировано.

Редактировать 2018-5-24

arglist также не работает в .NET Core. Кажется, что вызов функции C vararg устарел. Вместо этого вы должны использовать строковый API .NET, такой как String.Format.

person Jason Lee    schedule 05.01.2017

Есть веская причина, по которой функция, подобная scanf, отсутствует в С#. Он очень подвержен ошибкам и не гибок. Использование Regex гораздо более гибкое и мощное.

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

person sprite    schedule 22.06.2010

Я думаю, вам нужны функции библиотеки С# либо Parse, либо Convert.

// here's an example of getting the hex value from a command line 
// program.exe 0x00080000

static void Main(string[] args)
{
    int value = Convert.ToInt32(args[1].Substring(2), 16);
    Console.Out.WriteLine("Value is: " + value.ToString());
}
person Nichol Draper    schedule 30.09.2009

Вы можете использовать System.IO.FileStream и System.IO.StreamReader, а затем анализировать оттуда.

person SMB    schedule 23.01.2009
comment
Да, это обязательное условие для использования ReadLine, как предложил Митч Уит. - person Larry; 23.01.2009

Хотя это выглядит довольно грубо, оно выполняет свою работу:

// Create the stream reader
sr = new StreamReader("myFile.txt");

// Read it
srRec = sr.ReadLine();

// Replace multiple spaces with one space
String rec1 = srRec.Replace("          ", " ");
String rec2 = rec1.Replace("         ", " ");
String rec3 = rec2.Replace("        ", " ");
String rec4 = rec3.Replace("       ", " ");
String rec5 = rec4.Replace("      ", " ");
String rec6 = rec5.Replace("     ", " ");
String rec7 = rec6.Replace("    ", " ");
String rec8 = rec7.Replace("   ", " ");
String rec9 = rec8.Replace("  ", " ");

// Finally split the string into an array of strings with Split
String[] srVals = rec9.Split(' ');

Затем вы можете использовать массив srVals как отдельные переменные из записи.

person whatsRegex    schedule 06.01.2016
comment
Фу. У вас есть десять строк, которые можно заменить одной var srVals = srRec.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); для более предсказуемого поведения. Но это в стороне, это на самом деле не отвечает на вопрос. - person Peter Taylor; 04.05.2016