সি # তে কমান্ড-লাইন পরামিতিগুলিকে স্ট্রিং [] এ বিভক্ত স্ট্রিং


91

আমার একটি একক স্ট্রিং রয়েছে যাতে কমান্ড-লাইন প্যারামিটারগুলি অন্য একটি এক্সিকিউটেবলের কাছে প্রেরণ করা যায় এবং স্বতন্ত্র পরামিতিগুলি যুক্ত করে স্ট্রিংটি বের করতে হবে [C] যেভাবে কমান্ড-লাইনে কমান্ডগুলি নির্দিষ্ট করা হত। প্রতিবিম্বের মাধ্যমে অন্য কোনও অ্যাসেমব্লিজ এন্ট্রি-পয়েন্ট কার্যকর করতে গিয়ে স্ট্রিং [] ব্যবহার করা হবে।

এর জন্য কি কোনও স্ট্যান্ডার্ড ফাংশন আছে? বা পরামিতিগুলি সঠিকভাবে বিভক্ত করার জন্য কোনও পছন্দসই পদ্ধতি (রেজেক্স?) ​​রয়েছে? এটি অবশ্যই '' 'সীমান্তযুক্ত স্ট্রিংগুলিতে অবশ্যই পরিচালনা করবে যাতে স্পেসগুলি সঠিকভাবে থাকতে পারে, তাই আমি কেবল' 'এ বিভক্ত করতে পারি না।

উদাহরণ স্ট্রিং:

string parameterString = @"/src:""C:\tmp\Some Folder\Sub Folder"" /users:""abcdefg@hijkl.com"" tasks:""SomeTask,Some Other Task"" -someParam foo";

উদাহরণ ফলাফল:

string[] parameterArray = new string[] { 
  @"/src:C:\tmp\Some Folder\Sub Folder",
  @"/users:abcdefg@hijkl.com",
  @"tasks:SomeTask,Some Other Task",
  @"-someParam",
  @"foo"
};

আমার কোনও কমান্ড-লাইন পার্সিং গ্রন্থাগারের দরকার নেই, স্ট্রিংটি তৈরি করার কেবল একটি উপায় [] যা উত্পন্ন করা উচিত।

আপডেট : প্রকৃতপক্ষে সি # দ্বারা উত্পাদিত যা মেলানোর জন্য আমাকে প্রত্যাশিত ফলাফলটি পরিবর্তন করতে হয়েছিল (বিভক্ত স্ট্রিংগুলিতে অতিরিক্ত "সরিয়ে ফেলেছে)



4
প্রতিবার যখন কেউ সাড়া দেয় তখন মনে হয় আপনার পোস্টে না থাকা উপাদানের ভিত্তিতে আপত্তি রয়েছে। আমি আপনাকে এই উপাদানটি দিয়ে আপনার পোস্ট আপডেট করার পরামর্শ দিচ্ছি। আপনি আরও ভাল উত্তর পেতে পারেন।
tvanfosson

4
ভাল প্রশ্ন, একই খুঁজছেন। কাউকে "হে। নেট প্রকাশ করে যে এখানে ..." বলে খুঁজে পাওয়ার প্রত্যাশা ছিল :) আমি যদি কোনও সময়ে এসে পৌঁছে যাই তবে এটি এখানে পোস্ট করব, যদিও এটি years বছরের পুরানো। এখনও একটি বৈধ প্রশ্ন!
মাইকজ্যানসেন

আমিও এই ফাংশনটির প্রয়োজন হিসাবে আমি নীচে একটি উত্তরে একটি সম্পূর্ণরূপে পরিচালিত সংস্করণ তৈরি করেছি।
ygoe

উত্তর:


75

ছাড়াও ভাল এবং বিশুদ্ধ পরিচালিত সমাধান দ্বারা Earwicker , এটা মূল্য উল্লেখ সম্পূর্ণতার স্বার্থে হতে পারে, উইন্ডোজ এছাড়াও উপলব্ধ যে CommandLineToArgvWস্ট্রিং একটি অ্যারে মধ্যে একটি স্ট্রিং বিচ্ছেদ জন্য ফাংশন:

LPWSTR *CommandLineToArgvW(
    LPCWSTR lpCmdLine, int *pNumArgs);

একটি ইউনিকোড কমান্ড লাইন স্ট্রিংকে পার্স করে এবং স্ট্যান্ডার্ড সি রান-টাইম আরগভি এবং আরগিক মানগুলির অনুরূপ এমন আর্গুমেন্টের একটি গণনা সহ কমান্ড লাইন আর্গুমেন্টগুলিতে পয়েন্টারগুলির একটি অ্যারে প্রদান করে।

C # এর থেকে এই এপিআই কলিং এবং পরিচালিত কোড ফলে স্ট্রিং অ্যারে unpacking একটি উদাহরণ এ পাওয়া যেতে পারে, " args [] CommandLineToArgvW () API ব্যবহার করে রূপান্তর কম্যান্ড লাইন স্ট্রিং ।" নীচে একই কোডটির কিছুটা সহজ সংস্করণ দেওয়া হল:

[DllImport("shell32.dll", SetLastError = true)]
static extern IntPtr CommandLineToArgvW(
    [MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine, out int pNumArgs);

public static string[] CommandLineToArgs(string commandLine)
{
    int argc;
    var argv = CommandLineToArgvW(commandLine, out argc);        
    if (argv == IntPtr.Zero)
        throw new System.ComponentModel.Win32Exception();
    try
    {
        var args = new string[argc];
        for (var i = 0; i < args.Length; i++)
        {
            var p = Marshal.ReadIntPtr(argv, i * IntPtr.Size);
            args[i] = Marshal.PtrToStringUni(p);
        }

        return args;
    }
    finally
    {
        Marshal.FreeHGlobal(argv);
    }
}

4
এই ফাংশনটির জন্য আপনাকে উদ্ধৃতিগুলির অভ্যন্তরে কোনও পথের পিছনে পিছন দিক থেকে পালাতে হবে। স্ট্রিংটি সঠিকভাবে বিশ্লেষণের জন্য "সি: \ প্রোগ্রাম ফাইলগুলি \" হতে হবে "সি: Files প্রোগ্রাম ফাইল \\"।
ম্যাগনাস লিন্ধে

8
এটি লক্ষণীয় যে কমান্ডলাইনআর্গভিডাব্লুটি প্রথম যুক্তিটি প্রোগ্রামের নাম হিসাবে প্রত্যাশা করে এবং পার্সিং যাদু প্রয়োগ করা হয় না যদি এটি পাস না করা হয় তবে আপনি এ জাতীয় কিছু দিয়ে জাল করতে পারেন:CommandLineToArgs("foo.exe " + commandLine).Skip(1).ToArray();
স্কট ওয়েগনার

4
সম্পূর্ণতার জন্য, এমএসভিসিআরটি কমান্ডলাইন টিআআরজিভিডাব্লু () কমান্ড লাইনকে আরজিসি / আরজিভিতে রূপান্তর করতে ব্যবহার করে না। এটি নিজস্ব কোড ব্যবহার করে, যা আলাদা। উদাহরণস্বরূপ, এই স্ট্রিং সহ ক্রিয়েটপ্রসেসকে কল করার চেষ্টা করুন: একটি "বি সি" ডিএফ। মেন () আপনি 3 আর্গুমেন্ট পেতে চাই (দুটিই MSDN মধ্যে নথিভুক্ত যেমন), কিন্তু CommandLineToArgvW () / GetCommandLineW () কম্বো আপনি 2. দেব
LRN

7
ওএমজি এই রকম গোলযোগ। সাধারণ এমএস স্যুপ। কিছুই কিছুই ক্যানোনিকালাইজড হয় না এবং এম এস ওয়ার্ল্ডে কখনই কেআইএসএসকে সম্মান করা হয় না।
v.oddou

4
আমি মাইক্রোসফ্ট অনুবাদিত এমএসভিসিআরটি বাস্তবায়নের একটি ক্রস-প্ল্যাটফর্ম সংস্করণ এবং রেজেক্স ব্যবহার করে একটি উচ্চ-নির্ভুলতার আনুমানিক পোস্ট করেছি। আমি জানি এটি পুরানো, তবে আরে - কোনও শরীরের স্ক্রোল নেই।
টাইলার Y86

101

এটি আমাকে বিরক্ত করে যে প্রতিটি চরিত্র পরীক্ষা করে এমন ফাংশনের ভিত্তিতে স্ট্রিংকে বিভক্ত করার কোনও ফাংশন নেই। যদি সেখানে থাকে তবে আপনি এটি এটি লিখতে পারেন:

    public static IEnumerable<string> SplitCommandLine(string commandLine)
    {
        bool inQuotes = false;

        return commandLine.Split(c =>
                                 {
                                     if (c == '\"')
                                         inQuotes = !inQuotes;

                                     return !inQuotes && c == ' ';
                                 })
                          .Select(arg => arg.Trim().TrimMatchingQuotes('\"'))
                          .Where(arg => !string.IsNullOrEmpty(arg));
    }

যদিও এটি লেখা হয়েছে, কেন প্রয়োজনীয় বর্ধন পদ্ধতি লিখবেন না। ঠিক আছে, আপনি আমাকে এতে কথা বলেছেন ...

প্রথমত, আমার নিজের স্প্লিটের সংস্করণ যা একটি ফাংশন নেয় যা নির্দিষ্ট অক্ষরটি স্ট্রিংকে বিভক্ত করবে কিনা তা সিদ্ধান্ত নিতে হবে:

    public static IEnumerable<string> Split(this string str, 
                                            Func<char, bool> controller)
    {
        int nextPiece = 0;

        for (int c = 0; c < str.Length; c++)
        {
            if (controller(str[c]))
            {
                yield return str.Substring(nextPiece, c - nextPiece);
                nextPiece = c + 1;
            }
        }

        yield return str.Substring(nextPiece);
    }

এটি পরিস্থিতির উপর নির্ভর করে কিছু খালি স্ট্রিং পেতে পারে, তবে সম্ভবত সেই তথ্যটি অন্যান্য ক্ষেত্রে কার্যকর হবে, তাই আমি এই ফাংশনটির খালি এন্ট্রিগুলি সরিয়ে নেই।

দ্বিতীয়ত (এবং আরও জাগ্রতভাবে) একটি সামান্য সহায়ক যা কোনও স্ট্রিংয়ের শুরু এবং শেষের থেকে একটি মিলের জোড় কোট ছাঁটাই করবে। এটি স্ট্যান্ডার্ড ট্রিম পদ্ধতির চেয়ে আরও উদ্বেগজনক - এটি প্রতিটি প্রান্ত থেকে কেবল একটি চরিত্র ছাঁটাই করবে এবং এটি কেবল একটি প্রান্ত থেকে ছাঁটাবে না:

    public static string TrimMatchingQuotes(this string input, char quote)
    {
        if ((input.Length >= 2) && 
            (input[0] == quote) && (input[input.Length - 1] == quote))
            return input.Substring(1, input.Length - 2);

        return input;
    }

এবং আমি মনে করি আপনিও কিছু পরীক্ষা চাইবেন। ঠিক আছে, ঠিক আছে। তবে এটি অবশ্যই একেবারে শেষ জিনিস! প্রথমে একটি সহায়ক ফাংশন যা প্রত্যাশিত অ্যারে সামগ্রীর সাথে বিভাজনের ফলাফলের সাথে তুলনা করে:

    public static void Test(string cmdLine, params string[] args)
    {
        string[] split = SplitCommandLine(cmdLine).ToArray();

        Debug.Assert(split.Length == args.Length);

        for (int n = 0; n < split.Length; n++)
            Debug.Assert(split[n] == args[n]);
    }

তারপরে আমি এ জাতীয় পরীক্ষা লিখতে পারি:

        Test("");
        Test("a", "a");
        Test(" abc ", "abc");
        Test("a b ", "a", "b");
        Test("a b \"c d\"", "a", "b", "c d");

আপনার প্রয়োজনীয়তার জন্য পরীক্ষা এখানে:

        Test(@"/src:""C:\tmp\Some Folder\Sub Folder"" /users:""abcdefg@hijkl.com"" tasks:""SomeTask,Some Other Task"" -someParam",
             @"/src:""C:\tmp\Some Folder\Sub Folder""", @"/users:""abcdefg@hijkl.com""", @"tasks:""SomeTask,Some Other Task""", @"-someParam");

নোট করুন যে বাস্তবায়নের অতিরিক্ত বৈশিষ্ট্য রয়েছে যা এটি যদি কোনও তর্কযুক্ত করে তোলে তবে এটি ট্রিমম্যাচিংকোটিস ফাংশনটির জন্য ধন্যবাদ মুছে ফেলবে। আমি বিশ্বাস করি এটি সাধারণ কমান্ড-লাইন ব্যাখ্যার অংশ।


আমাকে উত্তর হিসাবে এটি চিহ্নিত করতে হয়েছিল কারণ আমার সঠিক প্রত্যাশিত আউটপুট নেই। আসল আউটপুটটির চূড়ান্ত অ্যারেতে থাকা উচিত নয়
আন্তন

16
আমি সর্বদা পরিবর্তিত প্রয়োজনীয়তা থেকে দূরে সরে যাওয়ার জন্য স্ট্যাক ওভারফ্লোতে এসেছি! :) আপনি সমস্ত উদ্ধৃতি থেকে মুক্তি পেতে ট্রিমম্যাচিংকোটিস () এর পরিবর্তে প্রতিস্থাপন ("\" "," ") ব্যবহার করতে পারেন But তবে উইন্ডোজ একটি উদ্ধৃতি চরিত্রটি অতিক্রম করার জন্য।" সমর্থন করে। " আমার স্প্লিট ফাংশন এটি করতে পারে না।
ড্যানিয়েল আর্উইকার

4
চমৎকার ওয়ান আর্ইউইকার :) অ্যান্টন: এটিই আমার সমাধানের পূর্বের পোস্টে আমি আপনাকে সমাধান করার চেষ্টা করছিলাম, তবে এটি লেখার ক্ষেত্রে আরউইকার আরও অনেক ভাল কাজ করেছেন;) এবং এটি অনেকটা প্রসারিত করেছেন;)
ইসরর খান

একটি সাদা স্থান কেবল কমান্ড লাইন আর্গুমেন্টগুলির জন্য পৃথককারী চরিত্র নয়, তাই না?
লুই রাইস

@ লুইস রাইস - আমি নিশ্চিত নই যদি এটি উদ্বেগ হয় তবে এটি সমাধান করা বেশ সহজ: char.IsWhiteSpaceপরিবর্তে ব্যবহার করুন== ' '
ড্যানিয়েল আরউইকার

25

উইন্ডোজ কমান্ড-লাইন পার্সারটি আপনার কথামতো ঠিক তেমন আচরণ করে, স্পেসে বিভক্ত হয়ে যদি না থাকে যার আগে তার কোনও উদ্ধৃত উদ্ধৃতি না থাকে। আমি নিজেই পার্সার লেখার সুপারিশ করব। এরকম কিছু হতে পারে:

    static string[] ParseArguments(string commandLine)
    {
        char[] parmChars = commandLine.ToCharArray();
        bool inQuote = false;
        for (int index = 0; index < parmChars.Length; index++)
        {
            if (parmChars[index] == '"')
                inQuote = !inQuote;
            if (!inQuote && parmChars[index] == ' ')
                parmChars[index] = '\n';
        }
        return (new string(parmChars)).Split('\n');
    }

4
আমি একই জিনিসটি বাদ দিয়ে শেষ করেছি, ব্যতীত আমি ব্যবহার করেছি S কাজ করছে বলে মনে হচ্ছে।
আন্তন

4
আমি ধরে নিয়েছি উইন্ডোজের অবশ্যই প্যারামিটারগুলিতে উদ্ধৃতি এড়াতে হবে ... এই অ্যালগরিদম এটিকে বিবেচনায় নেয় না।
রোমেডোর

ফাঁকা লাইনগুলি সরিয়ে ফেলা, বাইরের উক্তিগুলি সরিয়ে ফেলা এবং পালানো উদ্ধৃতিগুলি হ্যান্ডলিংয়ের পাঠকের পক্ষে বাড়াবাড়ি হিসাবে বাকি রয়েছে।
জেফরি এল হুইটলেজ

Char.IsWhiteSpace () এখানে সহায়তা করতে পারে
স্যাম ম্যাক্রিল

এই সমাধানটি ভাল যদি আর্গুমেন্টগুলি একক স্থান দ্বারা পৃথক করা হয় তবে ব্যর্থ হয় আর্গুমেন্টগুলি একাধিক স্পেস দ্বারা পৃথক করা হয়। : সঠিক সমাধান লিঙ্ক করুন stackoverflow.com/a/59131568/3926504
দিলীপ Nannaware

13

আমি জেফরি এল হুইটলেজের কাছ থেকে উত্তর নিয়েছি এবং এটি কিছুটা বাড়িয়েছি।

এটি এখন একক এবং ডাবল উভয় উদ্ধৃতি সমর্থন করে। আপনি অন্যান্য টাইপযুক্ত উদ্ধৃতি ব্যবহার করে প্যারামিটারগুলিতেই উদ্ধৃতিগুলি ব্যবহার করতে পারেন।

এটি আর্গুমেন্টগুলি থেকে উদ্ধৃতিগুলি কেড়ে নেয় কারণ এগুলি যুক্তি সম্পর্কিত তথ্যে অবদান রাখে না।

    public static string[] SplitArguments(string commandLine)
    {
        var parmChars = commandLine.ToCharArray();
        var inSingleQuote = false;
        var inDoubleQuote = false;
        for (var index = 0; index < parmChars.Length; index++)
        {
            if (parmChars[index] == '"' && !inSingleQuote)
            {
                inDoubleQuote = !inDoubleQuote;
                parmChars[index] = '\n';
            }
            if (parmChars[index] == '\'' && !inDoubleQuote)
            {
                inSingleQuote = !inSingleQuote;
                parmChars[index] = '\n';
            }
            if (!inSingleQuote && !inDoubleQuote && parmChars[index] == ' ')
                parmChars[index] = '\n';
        }
        return (new string(parmChars)).Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
    }

7

ভাল এবং বিশুদ্ধ পরিচালিত সমাধান দ্বারা Earwicker ভালো হ্যান্ডেল আর্গুমেন্ট করতে ব্যর্থ হয়েছে:

Test("\"He whispered to her \\\"I love you\\\".\"", "He whispered to her \"I love you\".");

এটি 3 উপাদান ফেরত:

"He whispered to her \"I
love
you\"."

সুতরাং "উদ্ধৃত escape" পালক \ "উদ্ধৃতি" সমর্থন করার জন্য এখানে একটি স্থিরতা রয়েছে:

public static IEnumerable<string> SplitCommandLine(string commandLine)
{
    bool inQuotes = false;
    bool isEscaping = false;

    return commandLine.Split(c => {
        if (c == '\\' && !isEscaping) { isEscaping = true; return false; }

        if (c == '\"' && !isEscaping)
            inQuotes = !inQuotes;

        isEscaping = false;

        return !inQuotes && Char.IsWhiteSpace(c)/*c == ' '*/;
        })
        .Select(arg => arg.Trim().TrimMatchingQuotes('\"').Replace("\\\"", "\""))
        .Where(arg => !string.IsNullOrEmpty(arg));
}

অতিরিক্ত 2 টি মামলা দিয়ে পরীক্ষিত:

Test("\"C:\\Program Files\"", "C:\\Program Files");
Test("\"He whispered to her \\\"I love you\\\".\"", "He whispered to her \"I love you\".");

এছাড়াও লক্ষনীয় যে গৃহীত উত্তর দ্বারা আতিফ আজিজ যা ব্যবহার CommandLineToArgvW এছাড়াও ব্যর্থ হয়েছে। এটি 4 টি উপাদান ফেরত দিয়েছে:

He whispered to her \ 
I 
love 
you". 

আশা করি এটি ভবিষ্যতে এইরকম সমাধান সন্ধান করতে কাউকে সহায়তা করবে।


4
উদ্বেগের জন্য দুঃখিত তবে এই সমাধানটি এখনও এমন জিনিসগুলিকে মিস করে না bla.exe aAAA"b\"ASDS\"c"dSADSDযার ফলাফল aAAAb"ASDS"cdSADSDযেখানে এই সমাধানটি আউটপুট দেয় aAAA"b"ASDS"c"dSADSD। আমি পরিবর্তন বিবেচনা করতে পারেন TrimMatchingQuotesএকটি থেকে Regex("(?<!\\\\)\\\"")এবং এটি ব্যবহার ভালো
স্কিস

4

4
দরকারী - তবে এটি আপনাকে কেবল বর্তমান প্রক্রিয়াতে কমান্ড লাইন আরোগুলি প্রেরণ করবে। প্রয়োজনীয়তাটি ছিল একটি স্ট্রিং থেকে একটি স্ট্রিং [] পাওয়ার জন্য একই পদ্ধতিতে "# কমান্ড-লাইনে যদি কমান্ডগুলি নির্দিষ্ট করা হত তবে সি # হবে "। আমার ধারণা, এমএস কীভাবে এটি প্রয়োগ করেছে তা দেখার জন্য আমরা একটি
ডিসকোপিলার

জোন গ্যাল্লোও যেমন খুঁজে পেয়েছেন ( ওয়েবলগস.এএসপি.এন. / জাগালোলো / অর্চিভ / ২০০ /0/ ০৯ /১ //২ ) একটি ডিসকম্পেলার খুব বেশি সাহায্য করে না যা আমাদের কাছে আতিফের উত্তরে ফিরে আসে ( স্ট্যাকওভারফ্লো / প্রশ্ন / 298830/… )
রোহানক্র্যাগ

4

আমি পুনরাবৃত্তিকারীদের পছন্দ করি এবং আজকাল লিনকিউIEnumerable<String> স্ট্রিংয়ের অ্যারেগুলির মতো সহজেই ব্যবহারযোগ্য করে তোলে , তাই আমার জেফ্রি এল হুইটলেজের উত্তরটির স্পিরিটি অনুসরণ করা (এতে এক্সটেনশন পদ্ধতি হিসাবে string):

public static IEnumerable<string> ParseArguments(this string commandLine)
{
    if (string.IsNullOrWhiteSpace(commandLine))
        yield break;

    var sb = new StringBuilder();
    bool inQuote = false;
    foreach (char c in commandLine) {
        if (c == '"' && !inQuote) {
            inQuote = true;
            continue;
        }

        if (c != '"' && !(char.IsWhiteSpace(c) && !inQuote)) {
            sb.Append(c);
            continue;
        }

        if (sb.Length > 0) {
            var result = sb.ToString();
            sb.Clear();
            inQuote = false;
            yield return result;
        }
    }

    if (sb.Length > 0)
        yield return sb.ToString();
}

3

আপনার প্রশ্নে আপনি একটি রেজেক্স চেয়েছিলেন, এবং আমি তাদের মধ্যে একটি বড় অনুরাগী এবং ব্যবহারকারী, সুতরাং যখন আপনার মতো এই একই যুক্তিটি বিভক্ত করার দরকার হয়েছিল, তখন আমি প্রায় গুগল করেছিলাম এবং একটি সহজ সমাধান খুঁজে না পাওয়ার পরে আমি আমার নিজের রেজেক্স লিখেছিলাম। আমি সংক্ষিপ্ত সমাধান পছন্দ করি, তাই আমি একটি তৈরি করেছি এবং এটি এখানে:

            var re = @"\G(""((""""|[^""])+)""|(\S+)) *";
            var ms = Regex.Matches(CmdLine, re);
            var list = ms.Cast<Match>()
                         .Select(m => Regex.Replace(
                             m.Groups[2].Success
                                 ? m.Groups[2].Value
                                 : m.Groups[4].Value, @"""""", @"""")).ToArray();

এটি উদ্ধৃতি চিহ্নগুলির মধ্যে ফাঁকা এবং উদ্ধৃতিগুলি পরিচালনা করে এবং "" এ সংযুক্ত "" রূপান্তর করে। কোডটি ব্যবহার করতে নির্দ্বিধায় অনুভব করুন!


3

ওহ হ্যাক সবই ... ইওহ তবে এটি বৈধ কর্মকর্তা। মাইক্রোসফ্ট থেকে নেট নেট জন্য সি # তে, সম্ভবত উইন্ডোজ, সম্ভবত ক্রস প্ল্যাটফর্ম, তবে এমআইটি লাইসেন্সপ্রাপ্ত।

জোয়ার, পদ্ধতি ঘোষণা এবং উল্লেখযোগ্য মন্তব্য নির্বাচন করুন;

internal static unsafe string[] InternalCreateCommandLine(bool includeArg0)
private static unsafe int SegmentCommandLine(char * pCmdLine, string[] argArray, bool includeArg0)
private static unsafe int ScanArgument0(ref char* psrc, char[] arg)
private static unsafe int ScanArgument(ref char* psrc, ref bool inquote, char[] arg)

-

// First, parse the program name (argv[0]). Argv[0] is parsed under special rules. Anything up to 
// the first whitespace outside a quoted subtring is accepted. Backslashes are treated as normal 
// characters.

-

// Rules: 2N backslashes + " ==> N backslashes and begin/end quote
//      2N+1 backslashes + " ==> N backslashes + literal "
//         N backslashes     ==> N backslashes

এই কোডটি .NET কোর থেকে পোষ্ট করা হয়। নেট ফ্রেমওয়ার্ক থেকে আমি যা অনুমান করি তা হয় এমএসভিসি সি লাইব্রেরি বা CommandLineToArgvW

নিয়মিত প্রকাশের সাথে কিছু শেননিগানকে পরিচালনা করার এবং যুক্তিটি শূন্য বিট উপেক্ষা করার জন্য আমার অর্ধাহীন প্রচেষ্টা। এটা একটু জাদুকরী।

private static readonly Regex RxWinArgs
  = new Regex("([^\\s\"]+\"|((?<=\\s|^)(?!\"\"(?!\"))\")+)(\"\"|.*?)*\"[^\\s\"]*|[^\\s]+",
    RegexOptions.Compiled
    | RegexOptions.Singleline
    | RegexOptions.ExplicitCapture
    | RegexOptions.CultureInvariant);

internal static IEnumerable<string> ParseArgumentsWindows(string args) {
  var match = RxWinArgs.Match(args);

  while (match.Success) {
    yield return match.Value;
    match = match.NextMatch();
  }
}

ভ্যাকি জেনারেট আউটপুট এ এটি মোটামুটি পরীক্ষা করেছে T বানরগুলি কী টাইপ করেছে এবং কীভাবে চালিয়েছে তার ন্যায্য শতাংশের সাথে এটির ফলাফল মিলে CommandLineToArgvW



4
হ্যাঁ মনে হচ্ছে সি # সংস্করণটি মারা গেছে। github.com/dotnet/runtime/blob/master/src/coreclr/src/utilcode/…
টাইলারওয়াই

4
সীমিত সময় পুনরুজ্জীবন। পেস্টবিন.
com

2

এই কোড প্রকল্প নিবন্ধটি আমি অতীতে ব্যবহার করেছি। এটি কোডের একটি ভাল বিট, তবে এটি কার্যকর হতে পারে।

এই এমএসডিএন নিবন্ধটি কেবলমাত্র আমি খুঁজে পেল যা সি # কমান্ড লাইনের যুক্তিগুলি কীভাবে পার্স করে তা ব্যাখ্যা করে।


আমি সি # লাইব্রেরিতে প্রতিবিম্বের চেষ্টা করেছি, তবে এটি একটি স্থানীয় সি ++ কলে যায় যে আমার কাছে কোড নেই এবং এটি পি-আহ্বান না করে কল করার কোনও উপায় দেখতে পাচ্ছে না। আমি একটি কমান্ড-লাইন পার্সিং লাইব্রেরিও চাই না, আমি কেবল স্ট্রিং চাই []।
অ্যান্টন

প্রতিবিম্বিত। নেট আমাকে কোথাও এনেছে। মধ্যে খুঁজছেন মনো উৎস কোড প্রস্তাব যে এই যুক্তি বিভাজন CLR দ্বারা নয় সম্পন্ন করা হয় বরং ইতিমধ্যে অপারেটিং সিস্টেম থেকে আসে। সি মূল ফাংশনের আরগসি, আরগভি পরামিতিগুলির কথা চিন্তা করুন। সুতরাং ওএস এপিআই ছাড়া আর পুনরায় ব্যবহার করার কিছুই নেই।
ygoe

2

যেহেতু আমি ওপি-র মতো একই আচরণ চেয়েছিলাম (উইন্ডোজ সেন্টিমিডির মতো একটি স্ট্রিং বিভক্ত করেছিলাম) আমি পরীক্ষাগুলির একগুচ্ছ লিখেছি এবং এখানে পোস্ট করা উত্তরগুলি পরীক্ষা করেছি:

    Test( 0, m, "One",                    new[] { "One" });
    Test( 1, m, "One ",                   new[] { "One" });
    Test( 2, m, " One",                   new[] { "One" });
    Test( 3, m, " One ",                  new[] { "One" });
    Test( 4, m, "One Two",                new[] { "One", "Two" });
    Test( 5, m, "One  Two",               new[] { "One", "Two" });
    Test( 6, m, "One   Two",              new[] { "One", "Two" });
    Test( 7, m, "\"One Two\"",            new[] { "One Two" });
    Test( 8, m, "One \"Two Three\"",      new[] { "One", "Two Three" });
    Test( 9, m, "One \"Two Three\" Four", new[] { "One", "Two Three", "Four" });
    Test(10, m, "One=\"Two Three\" Four", new[] { "One=Two Three", "Four" });
    Test(11, m, "One\"Two Three\" Four",  new[] { "OneTwo Three", "Four" });
    Test(12, m, "One\"Two Three   Four",  new[] { "OneTwo Three   Four" });
    Test(13, m, "\"One Two\"",            new[] { "One Two" });
    Test(14, m, "One\" \"Two",            new[] { "One Two" });
    Test(15, m, "\"One\"  \"Two\"",       new[] { "One", "Two" });
    Test(16, m, "One\\\"  Two",           new[] { "One\"", "Two" });
    Test(17, m, "\\\"One\\\"  Two",       new[] { "\"One\"", "Two" });
    Test(18, m, "One\"",                  new[] { "One" });
    Test(19, m, "\"One",                  new[] { "One" });
    Test(20, m, "One \"\"",               new[] { "One", "" });
    Test(21, m, "One \"",                 new[] { "One", "" });
    Test(22, m, "1 A=\"B C\"=D 2",        new[] { "1", "A=B C=D", "2" });
    Test(23, m, "1 A=\"B \\\" C\"=D 2",   new[] { "1", "A=B \" C=D", "2" });
    Test(24, m, "1 \\A 2",                new[] { "1", "\\A", "2" });
    Test(25, m, "1 \\\" 2",               new[] { "1", "\"", "2" });
    Test(26, m, "1 \\\\\" 2",             new[] { "1", "\\\"", "2" });
    Test(27, m, "\"",                     new[] { "" });
    Test(28, m, "\\\"",                   new[] { "\"" });
    Test(29, m, "'A B'",                  new[] { "'A", "B'" });
    Test(30, m, "^",                      new[] { "^" });
    Test(31, m, "^A",                     new[] { "A" });
    Test(32, m, "^^",                     new[] { "^" });
    Test(33, m, "\\^^",                   new[] { "\\^" });
    Test(34, m, "^\\\\", new[] { "\\\\" });
    Test(35, m, "^\"A B\"", new[] { "A B" });

    // Test cases Anton

    Test(36, m, @"/src:""C:\tmp\Some Folder\Sub Folder"" /users:""abcdefg@hijkl.com"" tasks:""SomeTask,Some Other Task"" -someParam foo", new[] { @"/src:C:\tmp\Some Folder\Sub Folder", @"/users:abcdefg@hijkl.com", @"tasks:SomeTask,Some Other Task", @"-someParam", @"foo" });

    // Test cases Daniel Earwicker 

    Test(37, m, "", new string[] { });
    Test(38, m, "a", new[] { "a" });
    Test(39, m, " abc ", new[] { "abc" });
    Test(40, m, "a b ", new[] { "a", "b" });
    Test(41, m, "a b \"c d\"", new[] { "a", "b", "c d" });

    // Test cases Fabio Iotti 

    Test(42, m, "this is a test ", new[] { "this", "is", "a", "test" });
    Test(43, m, "this \"is a\" test", new[] { "this", "is a", "test" });

    // Test cases Kevin Thach

    Test(44, m, "\"C:\\Program Files\"", new[] { "C:\\Program Files" });
    Test(45, m, "\"He whispered to her \\\"I love you\\\".\"", new[] { "He whispered to her \"I love you\"." });

"প্রত্যাশিত" মানটি সরাসরি আমার মেশিনে (win10 x64) এবং একটি সাধারণ মুদ্রণ প্রোগ্রামে cmd.exe দিয়ে এটি পরীক্ষা করে আসে:

static void Main(string[] args) => Console.Out.WriteLine($"Count := {args.Length}\n{string.Join("\n", args.Select((v,i) => $"[{i}] => '{v}'"))}");

এগুলি ফলাফল:


Solution                      | Failed Tests
------------------------------|------------------------------------- 
Atif Aziz (749653)            | 2, 3, 10, 11, 12, 14, 16, 17, 18, 26, 28, 31, 32, 33, 34, 35, 36, 37, 39, 45
Jeffrey L Whitledge (298968)  | 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 44, 45
Daniel Earwicker (298990)     | 10, 11, 12, 14, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 31, 32, 33, 34, 35, 36, 45
Anton (299795)                | 12, 16, 17, 18, 19, 21, 23, 25, 26, 27, 28, 31, 32, 33, 34, 35, 45
CS. (467313)                  | 12, 18, 19, 21, 27, 31, 32, 33, 34, 35
Vapour in the Alley (2132004) | 10, 11, 12, 14, 16, 17, 20, 21, 22, 23, 25, 26, 27, 28, 29, 31, 32, 33, 34, 35, 36, 45
Monoman (7774211)             | 14, 16, 17, 20, 21, 22, 23, 25, 26, 27, 28, 31, 32, 33, 34, 35, 45
Thomas Petersson (19091999)   | 2, 3, 10, 11, 12, 14, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 31, 32, 33, 34, 35, 36, 39, 45
Fabio Iotti (19725880)        | 1, 2, 3, 7, 10, 11, 12, 13, 14, 15, 16, 17, 19, 21, 22, 23, 25, 26, 28, 29, 30, 35, 36, 37, 39, 40, 42, 44, 45
ygoe (23961658)               | 26, 31, 32, 33, 34, 35
Kevin Thach (24829691)        | 10, 11, 12, 14, 18, 19, 20, 21, 22, 23, 26, 27, 31, 32, 33, 34, 35, 36
Lucas De Jesus (31621370)     | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45
HarryP (48008872)             | 24, 26, 31, 32, 33, 34, 35
TylerY86 (53290784)           | 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 31, 32, 33, 34, 35, 36, 41, 43, 44, 45
Louis Somers (55903304)       | 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 31, 32, 33, 34, 35, 36, 39, 41, 43, 44, 45
user2126375 (58233585)        | 5, 6, 15, 16, 17, 31, 32, 33, 34, 35
DilipNannaware (59131568)     | 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 44, 45
Mikescher (this)              | -

যেহেতু এখানে কোনও উত্তর সঠিক বলে মনে হয়নি (কমপক্ষে আমার ব্যবহারের কেসের ভিত্তিতে) এটি আমার সমাধান, এটি বর্তমানে সমস্ত পরীক্ষার কেস পাস করে (তবে কারও কাছে অতিরিক্ত (ব্যর্থ) কোণার কেস থাকলে দয়া করে মন্তব্য করুন):

public static IEnumerable<string> SplitArgs(string commandLine)
{
    var result = new StringBuilder();

    var quoted = false;
    var escaped = false;
    var started = false;
    var allowcaret = false;
    for (int i = 0; i < commandLine.Length; i++)
    {
        var chr = commandLine[i];

        if (chr == '^' && !quoted)
        {
            if (allowcaret)
            {
                result.Append(chr);
                started = true;
                escaped = false;
                allowcaret = false;
            }
            else if (i + 1 < commandLine.Length && commandLine[i + 1] == '^')
            {
                allowcaret = true;
            }
            else if (i + 1 == commandLine.Length)
            {
                result.Append(chr);
                started = true;
                escaped = false;
            }
        }
        else if (escaped)
        {
            result.Append(chr);
            started = true;
            escaped = false;
        }
        else if (chr == '"')
        {
            quoted = !quoted;
            started = true;
        }
        else if (chr == '\\' && i + 1 < commandLine.Length && commandLine[i + 1] == '"')
        {
            escaped = true;
        }
        else if (chr == ' ' && !quoted)
        {
            if (started) yield return result.ToString();
            result.Clear();
            started = false;
        }
        else
        {
            result.Append(chr);
            started = true;
        }
    }

    if (started) yield return result.ToString();
}

পরীক্ষার ফলাফল উত্পন্ন করতে আমি যে কোডটি ব্যবহার করেছি তা এখানে পাওয়া যাবে


1

একটি নিখুঁতভাবে পরিচালিত সমাধান সহায়ক হতে পারে। WINAPI ফাংশনের জন্য অনেকগুলি "সমস্যা" মন্তব্য রয়েছে এবং এটি অন্যান্য প্ল্যাটফর্মগুলিতে উপলব্ধ নেই। এখানে আমার কোডটির একটি সু-সংজ্ঞায়িত আচরণ রয়েছে (যা আপনি চাইলে পরিবর্তন করতে পারেন)।

এই string[] argsপ্যারামিটারটি সরবরাহ করার সময়। নেট / উইন্ডোজ যা করে তার মতোই করা উচিত এবং আমি এটি বেশ কয়েকটি "আকর্ষণীয়" মানগুলির সাথে তুলনা করি।

এটি একটি ক্লাসিক স্টেট-মেশিন বাস্তবায়ন যা প্রতিটি একক অক্ষরকে ইনপুট স্ট্রিং থেকে নেয় এবং বর্তমান অবস্থার জন্য এটি ব্যাখ্যা করে, আউটপুট উত্পাদন করে এবং একটি নতুন রাষ্ট্র। রাষ্ট্র ভেরিয়েবল সংজ্ঞায়িত করা হয় escape, inQuote, hadQuoteএবং prevCh, এবং আউটপুটে সংগৃহীত হয় currentArgএবং args

সত্যিকারের কমান্ড প্রম্পটে (উইন্ডোজ)) পরীক্ষাগুলি দ্বারা আবিষ্কার করা কয়েকটি বিশেষত্ব: উদ্ধৃত পরিসরের মধ্যে উত্পাদন , \\উত্পাদন \, \"উত্পাদন করে""""

^চরিত্র, ঐন্দ্রজালিক হবে বলে মনে হয় খুব: এটা সবসময় disappears যখন এটি দ্বিগুন না। অন্যথায় এটি সত্যিকারের কমান্ড লাইনে কোনও প্রভাব ফেলবে না। আমার বাস্তবায়ন এটি সমর্থন করে না, কারণ আমি এই আচরণের কোনও নমুনা পাইনি। এটি সম্পর্কে কেউ আরও জানতে পারে।

এই প্যাটার্নে খাপ খায় না এমন কিছু হ'ল নিম্নলিখিত আদেশটি:

cmd /c "argdump.exe "a b c""

cmdকমান্ড বাইরের কোট ধরা ও বাকি ধারণকৃত নিতে বলে মনে হয়। এটিতে কিছু বিশেষ যাদু সস থাকতে হবে।

আমি আমার পদ্ধতিতে কোনও মানদণ্ড সম্পন্ন করিনি, তবে এটিকে যুক্তিসঙ্গত দ্রুত বিবেচনা করুন। এটি Regexকোনও স্ট্রিং কনটেনটেশন ব্যবহার করে না এবং ব্যবহার করে না বরং পরিবর্তে StringBuilderএকটি আর্গুমেন্টের জন্য অক্ষর সংগ্রহ করতে একটি ব্যবহার করে এবং তাদের তালিকায় রাখে।

/// <summary>
/// Reads command line arguments from a single string.
/// </summary>
/// <param name="argsString">The string that contains the entire command line.</param>
/// <returns>An array of the parsed arguments.</returns>
public string[] ReadArgs(string argsString)
{
    // Collects the split argument strings
    List<string> args = new List<string>();
    // Builds the current argument
    var currentArg = new StringBuilder();
    // Indicates whether the last character was a backslash escape character
    bool escape = false;
    // Indicates whether we're in a quoted range
    bool inQuote = false;
    // Indicates whether there were quotes in the current arguments
    bool hadQuote = false;
    // Remembers the previous character
    char prevCh = '\0';
    // Iterate all characters from the input string
    for (int i = 0; i < argsString.Length; i++)
    {
        char ch = argsString[i];
        if (ch == '\\' && !escape)
        {
            // Beginning of a backslash-escape sequence
            escape = true;
        }
        else if (ch == '\\' && escape)
        {
            // Double backslash, keep one
            currentArg.Append(ch);
            escape = false;
        }
        else if (ch == '"' && !escape)
        {
            // Toggle quoted range
            inQuote = !inQuote;
            hadQuote = true;
            if (inQuote && prevCh == '"')
            {
                // Doubled quote within a quoted range is like escaping
                currentArg.Append(ch);
            }
        }
        else if (ch == '"' && escape)
        {
            // Backslash-escaped quote, keep it
            currentArg.Append(ch);
            escape = false;
        }
        else if (char.IsWhiteSpace(ch) && !inQuote)
        {
            if (escape)
            {
                // Add pending escape char
                currentArg.Append('\\');
                escape = false;
            }
            // Accept empty arguments only if they are quoted
            if (currentArg.Length > 0 || hadQuote)
            {
                args.Add(currentArg.ToString());
            }
            // Reset for next argument
            currentArg.Clear();
            hadQuote = false;
        }
        else
        {
            if (escape)
            {
                // Add pending escape char
                currentArg.Append('\\');
                escape = false;
            }
            // Copy character from input, no special meaning
            currentArg.Append(ch);
        }
        prevCh = ch;
    }
    // Save last argument
    if (currentArg.Length > 0 || hadQuote)
    {
        args.Add(currentArg.ToString());
    }
    return args.ToArray();
}

1

ব্যবহার:

public static string[] SplitArguments(string args) {
    char[] parmChars = args.ToCharArray();
    bool inSingleQuote = false;
    bool inDoubleQuote = false;
    bool escaped = false;
    bool lastSplitted = false;
    bool justSplitted = false;
    bool lastQuoted = false;
    bool justQuoted = false;

    int i, j;

    for(i=0, j=0; i<parmChars.Length; i++, j++) {
        parmChars[j] = parmChars[i];

        if(!escaped) {
            if(parmChars[i] == '^') {
                escaped = true;
                j--;
            } else if(parmChars[i] == '"' && !inSingleQuote) {
                inDoubleQuote = !inDoubleQuote;
                parmChars[j] = '\n';
                justSplitted = true;
                justQuoted = true;
            } else if(parmChars[i] == '\'' && !inDoubleQuote) {
                inSingleQuote = !inSingleQuote;
                parmChars[j] = '\n';
                justSplitted = true;
                justQuoted = true;
            } else if(!inSingleQuote && !inDoubleQuote && parmChars[i] == ' ') {
                parmChars[j] = '\n';
                justSplitted = true;
            }

            if(justSplitted && lastSplitted && (!lastQuoted || !justQuoted))
                j--;

            lastSplitted = justSplitted;
            justSplitted = false;

            lastQuoted = justQuoted;
            justQuoted = false;
        } else {
            escaped = false;
        }
    }

    if(lastQuoted)
        j--;

    return (new string(parmChars, 0, j)).Split(new[] { '\n' });
}

অ্যালির উত্তরের বাষ্পের উপর ভিত্তি করে , এটি একটি supports পলায়নকে সমর্থন করে।

উদাহরণ:

  • এটা একটা পরীক্ষা
    • এই
    • হয়
    • পরীক্ষা
  • এটা একটা পরীক্ষা
    • এই
    • ইহা একটি
    • পরীক্ষা
  • এটি ^ "একটি ^" পরীক্ষা
    • এই
    • "হয়
    • একটি "
    • পরীক্ষা
  • এটি "" "একটি" পরীক্ষা "
    • এই
    • اور
    • একটি পরীক্ষা

এটি একাধিক স্পেস সমর্থন করে (স্পেসের ব্লক প্রতি শুধুমাত্র একবারে যুক্তি ভঙ্গ করে)।


তিনটির মধ্যে শেষটি কোনওভাবে মার্কডাউনে হস্তক্ষেপ করে এবং উদ্দেশ্য হিসাবে রেন্ডার করা হয় না।
পিটার মর্টেনসেন

শূন্য-প্রস্থ-স্থান সহ স্থির।
ফ্যাবিও আইওটি

0

বর্তমানে, এই কোডটি আমার কাছে রয়েছে:

    private String[] SplitCommandLineArgument(String argumentString)
    {
        StringBuilder translatedArguments = new StringBuilder(argumentString);
        bool escaped = false;
        for (int i = 0; i < translatedArguments.Length; i++)
        {
            if (translatedArguments[i] == '"')
            {
                escaped = !escaped;
            }
            if (translatedArguments[i] == ' ' && !escaped)
            {
                translatedArguments[i] = '\n';
            }
        }

        string[] toReturn = translatedArguments.ToString().Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
        for(int i = 0; i < toReturn.Length; i++)
        {
            toReturn[i] = RemoveMatchingQuotes(toReturn[i]);
        }
        return toReturn;
    }

    public static string RemoveMatchingQuotes(string stringToTrim)
    {
        int firstQuoteIndex = stringToTrim.IndexOf('"');
        int lastQuoteIndex = stringToTrim.LastIndexOf('"');
        while (firstQuoteIndex != lastQuoteIndex)
        {
            stringToTrim = stringToTrim.Remove(firstQuoteIndex, 1);
            stringToTrim = stringToTrim.Remove(lastQuoteIndex - 1, 1); //-1 because we've shifted the indicies left by one
            firstQuoteIndex = stringToTrim.IndexOf('"');
            lastQuoteIndex = stringToTrim.LastIndexOf('"');
        }
        return stringToTrim;
    }

এটি পালিয়ে থাকা উক্তিগুলির সাথে কাজ করে না, তবে আমি এখন পর্যন্ত যেসব মামলার বিরুদ্ধে এসেছি তার ক্ষেত্রে এটি কাজ করে।


0

এটি অ্যান্টনের কোডের একটি উত্তর, যা পালানো উদ্ধৃতি দিয়ে কাজ করে না। আমি 3 টি স্থান পরিবর্তন করেছি।

  1. কন্সট্রাকটর জন্য StringBuilder মধ্যে SplitCommandLineArguments কোন প্রতিস্থাপন \ " সঙ্গে পান \ r
  2. ইন জন্য-লুপ মধ্যে SplitCommandLineArguments , আমি এখন প্রতিস্থাপন পান \ r চরিত্র ফিরে \ "
  3. স্প্লিটকম্যান্ডলাইনআর্গমেন্ট পদ্ধতিটি ব্যক্তিগত থেকে সর্বজনীন স্থিতিতে পরিবর্তিত হয়েছে ।

public static string[] SplitCommandLineArgument( String argumentString )
{
    StringBuilder translatedArguments = new StringBuilder( argumentString ).Replace( "\\\"", "\r" );
    bool InsideQuote = false;
    for ( int i = 0; i < translatedArguments.Length; i++ )
    {
        if ( translatedArguments[i] == '"' )
        {
            InsideQuote = !InsideQuote;
        }
        if ( translatedArguments[i] == ' ' && !InsideQuote )
        {
            translatedArguments[i] = '\n';
        }
    }

    string[] toReturn = translatedArguments.ToString().Split( new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries );
    for ( int i = 0; i < toReturn.Length; i++ )
    {
        toReturn[i] = RemoveMatchingQuotes( toReturn[i] );
        toReturn[i] = toReturn[i].Replace( "\r", "\"" );
    }
    return toReturn;
}

public static string RemoveMatchingQuotes( string stringToTrim )
{
    int firstQuoteIndex = stringToTrim.IndexOf( '"' );
    int lastQuoteIndex = stringToTrim.LastIndexOf( '"' );
    while ( firstQuoteIndex != lastQuoteIndex )
    {
        stringToTrim = stringToTrim.Remove( firstQuoteIndex, 1 );
        stringToTrim = stringToTrim.Remove( lastQuoteIndex - 1, 1 ); //-1 because we've shifted the indicies left by one
        firstQuoteIndex = stringToTrim.IndexOf( '"' );
        lastQuoteIndex = stringToTrim.LastIndexOf( '"' );
    }
    return stringToTrim;
}

আমি এই একই সমস্যাটি মোকাবেলা করছি, আপনি ভেবেছিলেন যে এই দিন এবং যুগে ইউনিট টেস্টিং কমান্ড লাইন আর্গুমেন্ট স্ট্রিংয়ের জন্য একটি সহজ সমাধান উপস্থিত থাকবে। আমি যে সমস্ত বিষয়ে নিশ্চিত হতে চাই তা হ'ল এমন একটি আচরণ যা প্রদত্ত কমান্ডলাইন আর্গুমেন্ট স্ট্রিংয়ের ফলাফল। আমি আপাতত ছেড়ে দিচ্ছি এবং স্ট্রিংয়ের জন্য ইউনিট পরীক্ষা তৈরি করব [] তবে এটি আবরণে কিছু সংহতকরণ পরীক্ষা যুক্ত করতে পারে।
চার্লি বার্কার

0

আমি মনে করি না সি # অ্যাপ্লিকেশনগুলির জন্য একক উদ্ধৃতি বা ^ কোট রয়েছে। নিম্নলিখিত ফাংশনটি আমার পক্ষে ভাল কাজ করছে:

public static IEnumerable<String> SplitArguments(string commandLine)
{
    Char quoteChar = '"';
    Char escapeChar = '\\';
    Boolean insideQuote = false;
    Boolean insideEscape = false;

    StringBuilder currentArg = new StringBuilder();

    // needed to keep "" as argument but drop whitespaces between arguments
    Int32 currentArgCharCount = 0;                  

    for (Int32 i = 0; i < commandLine.Length; i++)
    {
        Char c = commandLine[i];
        if (c == quoteChar)
        {
            currentArgCharCount++;

            if (insideEscape)
            {
                currentArg.Append(c);       // found \" -> add " to arg
                insideEscape = false;
            }
            else if (insideQuote)
            {
                insideQuote = false;        // quote ended
            }
            else
            {
                insideQuote = true;         // quote started
            }
        }
        else if (c == escapeChar)
        {
            currentArgCharCount++;

            if (insideEscape)   // found \\ -> add \\ (only \" will be ")
                currentArg.Append(escapeChar + escapeChar);       

            insideEscape = !insideEscape;
        }
        else if (Char.IsWhiteSpace(c))
        {
            if (insideQuote)
            {
                currentArgCharCount++;
                currentArg.Append(c);       // append whitespace inside quote
            }
            else
            {
                if (currentArgCharCount > 0)
                    yield return currentArg.ToString();

                currentArgCharCount = 0;
                currentArg.Clear();
            }
        }
        else
        {
            currentArgCharCount++;
            if (insideEscape)
            {
                // found non-escaping backslash -> add \ (only \" will be ")
                currentArg.Append(escapeChar);                       
                currentArgCharCount = 0;
                insideEscape = false;
            }
            currentArg.Append(c);
        }
    }

    if (currentArgCharCount > 0)
        yield return currentArg.ToString();
}

0

আমি গতকাল পোস্ট করা কোডটি একবার দেখে নিতে পারি:

[সি #] পাথ এবং যুক্তিগুলির স্ট্রিং

এটি একটি ফাইলের নাম + যুক্তিগুলিকে স্ট্রিং [] এ বিভক্ত করে। সংক্ষিপ্ত পথ, পরিবেশের ভেরিয়েবল এবং অনুপস্থিত ফাইল এক্সটেনশনগুলি পরিচালনা করা হয়।

(প্রাথমিকভাবে এটি আনস্ট্রিস্ট্রিস্ট রেজিস্ট্রিতে ছিল))


0

এই কোড ব্যবহার করে দেখুন:

    string[] str_para_linha_comando(string str, out int argumentos)
    {
        string[] linhaComando = new string[32];
        bool entre_aspas = false;
        int posicao_ponteiro = 0;
        int argc = 0;
        int inicio = 0;
        int fim = 0;
        string sub;

        for(int i = 0; i < str.Length;)
        {
            if (entre_aspas)
            {
                // Está entre aspas
                sub = str.Substring(inicio+1, fim - (inicio+1));
                linhaComando[argc - 1] = sub;

                posicao_ponteiro += ((fim - posicao_ponteiro)+1);
                entre_aspas = false;
                i = posicao_ponteiro;
            }
            else
            {
            tratar_aspas:
                if (str.ElementAt(i) == '\"')
                {
                    inicio = i;
                    fim = str.IndexOf('\"', inicio + 1);
                    entre_aspas = true;
                    argc++;
                }
                else
                {
                    // Se não for aspas, então ler até achar o primeiro espaço em branco
                    if (str.ElementAt(i) == ' ')
                    {
                        if (str.ElementAt(i + 1) == '\"')
                        {
                            i++;
                            goto tratar_aspas;
                        }

                        // Pular os espaços em branco adiconais
                        while(str.ElementAt(i) == ' ') i++;

                        argc++;
                        inicio = i;
                        fim = str.IndexOf(' ', inicio);
                        if (fim == -1) fim = str.Length;
                        sub = str.Substring(inicio, fim - inicio);
                        linhaComando[argc - 1] = sub;
                        posicao_ponteiro += (fim - posicao_ponteiro);

                        i = posicao_ponteiro;
                        if (posicao_ponteiro == str.Length) break;
                    }
                    else
                    {
                        argc++;
                        inicio = i;
                        fim = str.IndexOf(' ', inicio);
                        if (fim == -1) fim = str.Length;

                        sub = str.Substring(inicio, fim - inicio);
                        linhaComando[argc - 1] = sub;
                        posicao_ponteiro += fim - posicao_ponteiro;
                        i = posicao_ponteiro;
                        if (posicao_ponteiro == str.Length) break;
                    }
                }
            }
        }

        argumentos = argc;

        return linhaComando;
    }

এটি পর্তুগিজ ভাষায় লেখা।


বরং ডকুমেন্টেশনটি পর্তুগিজ
এনামুল হাসান

@ এ্যামনুলহসান আমি বলব কোডটি পর্তুগিজ ভাষায়ও রয়েছে, যেমন posicao_ponteiro += ((fim - posicao_ponteiro)+1);
মেমার্ক

0

এখানে একটি লাইনার রয়েছে যা কাজটি সম্পন্ন করে (একটি লাইন দেখুন যা বুর্স্টকমিডলাইনআর্গস (...) পদ্ধতির অভ্যন্তরে সমস্ত কাজ করে)।

আমি কোডের সর্বাধিক পঠনযোগ্য লাইনকে কল করব না, তবে আপনি পঠনযোগ্যতার জন্য এটিকে ছিন্ন করতে পারেন। এটি উদ্দেশ্য হিসাবে সহজ এবং সমস্ত আর্গুমেন্ট কেসগুলির জন্য ভাল কাজ করে না (যেমন ফাইলের নাম আর্গুমেন্টগুলিতে যার মধ্যে বিভক্ত স্ট্রিং চরিত্রের ডিলিমিটার রয়েছে)।

এই সমাধানটি এটি ব্যবহার করে এমন আমার সমাধানগুলিতে ভাল কাজ করেছে। যেমনটি আমি বলেছিলাম, প্রতিটি সম্ভাব্য যুক্তি বিন্যাস এন-ফ্যাকটোরিয়াল পরিচালনা করতে ইঁদুরের কোডের বাসা ছাড়াই কাজটি হয়ে যায়।

using System;
using System.Collections.Generic;
using System.Linq;

namespace CmdArgProcessor
{
    class Program
    {
        static void Main(string[] args)
        {
            // test switches and switches with values
            // -test1 1 -test2 2 -test3 -test4 -test5 5

            string dummyString = string.Empty;

            var argDict = BurstCmdLineArgs(args);

            Console.WriteLine("Value for switch = -test1: {0}", argDict["test1"]);
            Console.WriteLine("Value for switch = -test2: {0}", argDict["test2"]);
            Console.WriteLine("Switch -test3 is present? {0}", argDict.TryGetValue("test3", out dummyString));
            Console.WriteLine("Switch -test4 is present? {0}", argDict.TryGetValue("test4", out dummyString));
            Console.WriteLine("Value for switch = -test5: {0}", argDict["test5"]);

            // Console output:
            //
            // Value for switch = -test1: 1
            // Value for switch = -test2: 2
            // Switch -test3 is present? True
            // Switch -test4 is present? True
            // Value for switch = -test5: 5
        }

        public static Dictionary<string, string> BurstCmdLineArgs(string[] args)
        {
            var argDict = new Dictionary<string, string>();

            // Flatten the args in to a single string separated by a space.
            // Then split the args on the dash delimiter of a cmd line "switch".
            // E.g. -mySwitch myValue
            //  or -JustMySwitch (no value)
            //  where: all values must follow a switch.
            // Then loop through each string returned by the split operation.
            // If the string can be split again by a space character,
            // then the second string is a value to be paired with a switch,
            // otherwise, only the switch is added as a key with an empty string as the value.
            // Use dictionary indexer to retrieve values for cmd line switches.
            // Use Dictionary::ContainsKey(...) where only a switch is recorded as the key.
            string.Join(" ", args).Split('-').ToList().ForEach(s => argDict.Add(s.Split()[0], (s.Split().Count() > 1 ? s.Split()[1] : "")));

            return argDict;
        }
    }
}

0

আমার এখানে পছন্দ করা কিছু খুঁজে পাইনি। আমি একটি ছোট কমান্ড-লাইনের জন্য ফলন যাদু দিয়ে স্ট্যাকের গণ্ডগোল ঘৃণা করতে ঘৃণা করি (এটি যদি কোনও টেরাবাইটের স্রোত হয় তবে এটি অন্য গল্প হবে)।

এখানে আমার গ্রহণ, এটি এই জাতীয় ডাবল উদ্ধৃতি দিয়ে উদ্ধৃতি সমর্থন করে:

প্যারাম = "একটি 15" "স্ক্রিনটি খারাপ নয়" প্যারাম 2 = 'এ 15 "স্ক্রিন খারাপ নয়' প্যারাম 3 =" "প্যারাম 4 = / প্যারাম 5

ফলাফল:

পরম = "একটি 15" স্ক্রিনটি খারাপ নয় "

প্যারাম 2 = 'এ 15' স্ক্রিনটি খারাপ নয় '

প্যারাম 3 = ""

param4 =

/ প্যারাম 5

public static string[] SplitArguments(string commandLine)
{
    List<string> args         = new List<string>();
    List<char>   currentArg   = new List<char>();
    char?        quoteSection = null; // Keeps track of a quoted section (and the type of quote that was used to open it)
    char[]       quoteChars   = new[] {'\'', '\"'};
    char         previous     = ' '; // Used for escaping double quotes

    for (var index = 0; index < commandLine.Length; index++)
    {
        char c = commandLine[index];
        if (quoteChars.Contains(c))
        {
            if (previous == c) // Escape sequence detected
            {
                previous = ' '; // Prevent re-escaping
                if (!quoteSection.HasValue)
                {
                    quoteSection = c; // oops, we ended the quoted section prematurely
                    continue;         // don't add the 2nd quote (un-escape)
                }

                if (quoteSection.Value == c)
                    quoteSection = null; // appears to be an empty string (not an escape sequence)
            }
            else if (quoteSection.HasValue)
            {
                if (quoteSection == c)
                    quoteSection = null; // End quoted section
            }
            else
                quoteSection = c; // Start quoted section
        }
        else if (char.IsWhiteSpace(c))
        {
            if (!quoteSection.HasValue)
            {
                args.Add(new string(currentArg.ToArray()));
                currentArg.Clear();
                previous = c;
                continue;
            }
        }

        currentArg.Add(c);
        previous = c;
    }

    if (currentArg.Count > 0)
        args.Add(new string(currentArg.ToArray()));

    return args.ToArray();
}

0

আমি রাষ্ট্রীয় মেশিনকে একই পার্সার ফলাফল হিসাবে বাস্তবায়িত করেছি যেনাগারগুলি নেট নেট অ্যাপ্লিকেশনটিতে পাস হবে এবং static void Main(string[] args)পদ্ধতিতে প্রক্রিয়াভুক্ত হবে ।

    public static IList<string> ParseCommandLineArgsString(string commandLineArgsString)
    {
        List<string> args = new List<string>();

        commandLineArgsString = commandLineArgsString.Trim();
        if (commandLineArgsString.Length == 0)
            return args;

        int index = 0;
        while (index != commandLineArgsString.Length)
        {
            args.Add(ReadOneArgFromCommandLineArgsString(commandLineArgsString, ref index));
        }

        return args;
    }

    private static string ReadOneArgFromCommandLineArgsString(string line, ref int index)
    {
        if (index >= line.Length)
            return string.Empty;

        var sb = new StringBuilder(512);
        int state = 0;
        while (true)
        {
            char c = line[index];
            index++;
            switch (state)
            {
                case 0: //string outside quotation marks
                    if (c == '\\') //possible escaping character for quotation mark otherwise normal character
                    {
                        state = 1;
                    }
                    else if (c == '"') //opening quotation mark for string between quotation marks
                    {
                        state = 2;
                    }
                    else if (c == ' ') //closing arg
                    {
                        return sb.ToString();
                    }
                    else
                    {
                        sb.Append(c);
                    }

                    break;
                case 1: //possible escaping \ for quotation mark or normal character
                    if (c == '"') //If escaping quotation mark only quotation mark is added into result
                    {
                        state = 0;
                        sb.Append(c);
                    }
                    else // \ works as not-special character
                    {
                        state = 0;
                        sb.Append('\\');
                        index--;
                    }

                    break;
                case 2: //string between quotation marks
                    if (c == '"') //quotation mark in string between quotation marks can be escape mark for following quotation mark or can be ending quotation mark for string between quotation marks
                    {
                        state = 3;
                    }
                    else if (c == '\\') //escaping \ for possible following quotation mark otherwise normal character
                    {
                        state = 4;
                    }
                    else //text in quotation marks
                    {
                        sb.Append(c);
                    }

                    break;
                case 3: //quotation mark in string between quotation marks
                    if (c == '"') //Quotation mark after quotation mark - that means that this one is escaped and can added into result and we will stay in string between quotation marks state
                    {
                        state = 2;
                        sb.Append(c);
                    }
                    else //we had two consecutive quotation marks - this means empty string but the following chars (until space) will be part of same arg result as well
                    {
                        state = 0;
                        index--;
                    }

                    break;
                case 4: //possible escaping \ for quotation mark or normal character in string between quotation marks
                    if (c == '"') //If escaping quotation mark only quotation mark added into result
                    {
                        state = 2;
                        sb.Append(c);
                    }
                    else
                    {
                        state = 2;
                        sb.Append('\\');
                        index--;
                    }

                    break;
            }

            if (index == line.Length)
                return sb.ToString();
        }
    }

0

এখানে সমাধানটি স্থান (গুলি) (একক বা একাধিক স্পেস) কমান্ড লাইন প্যারামিটার বিভাজক হিসাবে বিবেচনা করে এবং প্রকৃত কমান্ড লাইন আর্গুমেন্ট প্রদান করে:

static string[] ParseMultiSpacedArguments(string commandLine)
{
    var isLastCharSpace = false;
    char[] parmChars = commandLine.ToCharArray();
    bool inQuote = false;
    for (int index = 0; index < parmChars.Length; index++)
    {
        if (parmChars[index] == '"')
            inQuote = !inQuote;
        if (!inQuote && parmChars[index] == ' ' && !isLastCharSpace)
            parmChars[index] = '\n';

        isLastCharSpace = parmChars[index] == '\n' || parmChars[index] == ' ';
    }

    return (new string(parmChars)).Split('\n');
}

0

এখানে একটি নিউগেট প্যাকেজ রয়েছে যা আপনার প্রয়োজন ঠিক ঠিক কার্যকারিতা সহ:

Microsoft.CodeAnalysis.Common বর্গ রয়েছে CommandLineParser পদ্ধতি সঙ্গে SplitCommandLineIntoArguments

আপনি এটি এর মতো ব্যবহার করুন:

using Microsoft.CodeAnalysis;
// [...]
var cli = @"/src:""C:\tmp\Some Folder\Sub Folder"" /users:""abcdefg@hijkl.com"" tasks:""SomeTask,Some Other Task"" -someParam foo";
var cliArgs = CommandLineParser.SplitCommandLineIntoArguments(cli, true);

Console.WriteLine(string.Join('\n', cliArgs));
// prints out:
// /src:"C:\tmp\Some Folder\Sub Folder"
// /users:"abcdefg@hijkl.com"
// tasks:"SomeTask,Some Other Task"
// -someParam
// foo

-2

আমি আপনাকে বুঝতে পেরেছি কিনা তা নিশ্চিত নই, তবে চরিত্রটি স্প্লিটার হিসাবে ব্যবহৃত হয়েছে, এটিও পাঠ্যের ভিতরে পাওয়া যাবে? (এটি বাদে এটি "ডাবল" দিয়ে পালাতে পারে?)

যদি তাই হয় তবে আমি একটি তৈরি করব for লুপ এবং <"> </> (বা অন্য কোনও" নিরাপদ "চরিত্রের সাথে উপস্থিত সমস্ত দৃষ্টান্ত প্রতিস্থাপন করব তবে নিশ্চিত করে নিন যে এটি কেবল <"> প্রতিস্থাপন করে, <""> নয়)

স্ট্রিংটির পুনরাবৃত্তি করার পরে, আমি আগে পোস্ট করা হিসাবে স্ট্রিং বিভক্ত করা হবে, তবে এখন <|> অক্ষর।


ডাবল "" এর তার @ @ .. "স্ট্রিং আক্ষরিক, ডাবল" এর "@" এর ভিতরে .. "স্ট্রিংটি একটি সাধারণ স্ট্রিংয়ের" পলায়ন "এর সমতুল্য
আন্তন

"একমাত্র বিধিনিষেধ (আমি অবহেলিত) হ'ল স্ট্রিংগুলি স্পেস-সীমাবদ্ধ, যদি না" ... "ব্লক" এর মধ্যে স্থান সজ্জিত করে -> বাজুকার সাহায্যে কোনও পাখির শুটিং করা হতে পারে, তবে একটি বুলিয়ান রাখুন যা "সত্য" হয়ে যায় যখন "সত্য" থাকাকালীন কোনও উদ্ধৃতিতে এবং যদি কোনও স্থান ভিতরে সন্ধান করা হয় তবে চালিয়ে যান, অন্যথায় <> = <|>
ইসরার খান

-6

হ্যাঁ, স্ট্রিং অবজেক্টটির একটি বিল্ট ইন ফাংশন রয়েছে যা Split()ডিলিমিটার হিসাবে সন্ধান করার জন্য চরিত্রটি নির্দিষ্ট করে এমন একক প্যারামিটার নেয় এবং এতে পৃথক মানগুলির সাথে স্ট্রিংগুলির একটি অ্যারে (স্ট্রিং []) প্রদান করে।


4
এটি src বিভক্ত করবে: "সি: \ tmp \ কিছু ফোল্ডার \ সাব ফোল্ডার" অংশটি ভুলভাবে।
অ্যান্টন

স্ট্রিংয়ের ভিতরে থাকা উদ্ধৃতিগুলি সম্পর্কে কী যা অস্থায়ীভাবে স্পেসগুলিতে বিভাজন বন্ধ করে দেয়?
ড্যানিয়েল আর্উইকার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.