Come analizzare una riga di comando con le espressioni regolari?

Voglio dividere una riga di comando simile a stringa singola stringa di parametri. Come guardare l’espressione regolare per farlo. Il problema è che i parametri possono essere indicati. Come ad esempio:

“param 1” param2 “param 3”

dovrebbe comportare:

param 1, param2, param 3

InformationsquelleAutor Horcrux7 | 2008-10-13



13 Replies
  1. 14

    Non si dovrebbe usare le espressioni regolari per questo. Scrivere un parser invece, o utilizzare quello fornito dalla vostra lingua.

    Non vedo perché downvoted per questo. Questo è come potrebbe essere fatto in Python:

    >>> import shlex
    >>> shlex.split('"param 1" param2 "param 3"')
    ['param 1', 'param2', 'param 3']
    >>> shlex.split('"param 1" param2 "param 3')
    Traceback (most recent call last):
        [...]
    ValueError: No closing quotation
    >>> shlex.split('"param 1" param2 "param 3\\""')
    ['param 1', 'param2', 'param 3"']

    Ora mi dicono che distruggendo il cervello su come una espressione regolare è di risolvere questo problema è sempre valga la pena.

    • Sono d’accordo. Questa sarebbe una soluzione migliore, soprattutto se avete bisogno di mettere le virgolette all’interno della stringa: “param””1” param2…
    • +1 – come il parsing di XML, questo non è un problema per le espressioni regolari.
    • Sciocchezza assoluta. Questo è un semplice problema di espressioni regolari, e non ha nulla in comune con il parsing di XML.
    • shelx deve essere la risposta, d’accordo con hop ! questo è così vero !
    • Nel mio caso ne vale la pena, perché: ho bisogno che in alcuni psql script, e l’alternativa sarebbe una seccatura con plpgsql.
  2. 5

    Senza riguardo per l’attuazione di una lingua, la tua regex potrebbe essere qualcosa di simile a questo:

    ("[^"]*"|[^"]+)(\s+|$)

    La prima parte "[^"]*" cerca una stringa tra virgolette che non contengono i preventivi, e la seconda parte [^"]+ cerca una sequenza di non citare personaggi. Il \s+ corrisponde a una separazione sequenza di spazi, e $ indica la fine di una stringa.

    • In cui regex dialetto fa un|$ lavoro? Deve essere \z
    • Che sempre lavorato per me in Python e Perl.
    • Vero, sono andato in confusione.
    • Caso di fallimento per le regex: <” ” param2 “” bozo “bonazza” “param 3”> bando di gara 1) citazioni a sinistra nella risposta 2) include finale spazio dopo bozo. Probabilmente ha altri bug di troppo.
    • Spiacenti questi commenti ritaglia spazi ci dovrebbe essere un sacco di spazi dopo “bozo”.
  3. 4
    ("[^"]+"|[^\s"]+)

    quello che io uso
    C++

    #include <iostream>
    #include <iterator>
    #include <string>
    #include <regex>
    
    void foo()
    {
        std::string strArg = " \"par   1\"  par2 par3 \"par 4\""; 
    
        std::regex word_regex( "(\"[^\"]+\"|[^\\s\"]+)" );
        auto words_begin = 
            std::sregex_iterator(strArg.begin(), strArg.end(), word_regex);
        auto words_end = std::sregex_iterator();
        for (std::sregex_iterator i = words_begin; i != words_end; ++i)
        {
            std::smatch match = *i;
            std::string match_str = match.str();
            std::cout << match_str << '\n';
        }
    }

    Di uscita:

    "par   1"
    par2
    par3
    "par 4"
    • Proprio quello che stavo cercando, grazie!
  4. 2

    La maggior parte delle lingue sono altre funzioni (o built-in o fornito da una libreria standard) che analizza le righe di comando molto più facilmente di costruire il proprio regex, oltre a sapere che verranno farlo con precisione, fuori dalla scatola. Se si modifica il tuo post per identificare la lingua che si sta utilizzando, sono sicuro che qualcuno qui sarà in grado di punto a quello utilizzato in quella lingua.

    Espressioni regolari sono strumenti molto potenti e utili per una vasta gamma di cose, ma ci sono anche molti problemi per i quali non siano la soluzione migliore. Questo è uno di loro.

  5. 1

    Per suddividere un file exe da params; stripping parentesi all’exe; assume pulire i dati:

    ^(?:"([^"]+(?="))|([^\s]+))["]{0,1} +(.+)$

    Si avranno due partite alla volta, di tre match gruppi:

    1. L’exe se era avvolto nella parentesi
    2. L’exe se non era avvolto in parentesi
    3. Il ciuffo di parametri

    Esempi:

    "C:\WINDOWS\system32\cmd.exe" /c echo this

    Corrispondenza 1: C:\WINDOWS\system32\cmd.exe

    Match 2: $null

    Partita 3: /c echo this

    C:\WINDOWS\system32\cmd.exe /c echo this

    Corrispondenza 1: $null

    Match 2: C:\WINDOWS\system32\cmd.exe

    Partita 3: /c echo this

    "C:\Program Files\foo\bar.exe" /run

    Corrispondenza 1: C:\Program Files\foo\bar.exe

    Match 2: $null

    Partita 3: /run

    Pensieri:

    Sono abbastanza sicuro che è necessario per creare un ciclo per la cattura di un eventuale numero infinito di parametri.

    Questa espressione regolare può essere facilmente messo in loop sul terzo match fino a quando la partita non riesce, non ci sono più params.

  6. 1

    Regex: /[\/-]?((\w+)(?:[=:]("[^"]+"|[^\s"]+))?)(?:\s+|$)/g

    Esempio: /P1="Long value" /P2=3 /P3=short PwithoutSwitch1=any PwithoutSwitch2

    Tale espressione regolare può analizza l’elenco dei parametri che costruito da regole:

    • Parametri sono separati da spazi (uno o più).
    • Parametro può contiene interruttore simbolo (/ o -).
    • Parametro è costituito dal nome e il valore che divide con il simbolo = o :.
    • Nome può essere il set di caratteri alfanumerici e caratteri di sottolineatura.
    • Valore può assenti.
    • Se il valore esiste, può essere l’insieme di tutti i simboli, ma se si ha lo spazio, quindi il valore dovrebbe essere citato.

    Questa regex ha tre gruppi:

    • il primo gruppo contiene i parametri senza passare simbolo,
    • il secondo gruppo contiene solo il nome,
    • il terzo gruppo contiene un valore (se esiste) solo.

    Per esempio precedente:

    1. Tutta la partita: /P1="Long value"
      • Gruppo#1: P1="Long value",
      • Gruppo#2: P1,
      • Gruppo#3: "Long value".
    2. Tutta la partita: /P2=3
      • Gruppo#1: P2=3,
      • Gruppo#2: P2,
      • Gruppo#3: 3.
    3. Tutta la partita: /P3=short
      • Gruppo#1: P3=short,
      • Gruppo#2: P3,
      • Gruppo#3: short.
    4. Tutta la partita: PwithoutSwitch1=any
      • Gruppo#1: PwithoutSwitch1=any,
      • Gruppo#2: PwithoutSwitch1,
      • Gruppo#3: any.
    5. Tutta la partita: PwithoutSwitch2
      • Gruppo#1: PwithoutSwitch2,
      • Gruppo#2: PwithoutSwitch2,
      • Gruppo#3: assenti.
  7. 0

    Qualcosa di simile:

    "(?:(?<=")([^"]+)"\s*)|\s*([^"\s]+)

    o una più semplice:

    "([^"]+)"|\s*([^"\s]+)

    (solo per il bene di trovare una regexp 😉 )

    Applicare più di una volta, e il gruppo n°1 vi darà il parametro, se esso è racchiuso tra virgolette doppie o non.

  8. 0

    Se le quotazioni si sono preoccupati, quindi basta scrivere un semplice ciclo di dump di carattere per carattere in una stringa ignorando le virgolette.

    In alternativa, se si utilizza la manipolazione di stringhe, biblioteca, si può utilizzare per rimuovere tutte le offerte e concatenarle.

  9. 0

    Se si sta cercando di analizzare il comando e i parametri utilizzare il seguente (^$ corrispondenti a interruzioni di riga aka multiline):

    (?<cmd>^"[^"]*"|\S*) *(?<prm>.*)?

    Nel caso In cui si desidera utilizzare nel vostro codice C#, qui è correttamente sfuggito:

    try {
        Regex RegexObj = new Regex("(?<cmd>^\\\"[^\\\"]*\\\"|\\S*) *(?<prm>.*)?");
    
    } catch (ArgumentException ex) {
        //Syntax error in the regular expression
    }

    Analizza la seguente e sapere qual è il comando contro i parametri:

    "c:\program files\myapp\app.exe" p1 p2 "p3 with space"
    app.exe p1 p2 "p3 with space"
    app.exe
  10. 0

    c’è un pitone risposta così avremo un rubino risposta 🙂

    require 'shellwords'
    Shellwords.shellsplit '"param 1" param2 "param 3"'
    #=> ["param 1", "param2", "param 3"] or :
    '"param 1" param2 "param 3"'.shellsplit
  11. 0
    \s*("[^"]+"|[^\s"]+)

    che è

    • Questa domanda è di 4 anni e già picchiato a morte.
    • ma nessuna risposta mi ha soddisfatto
    • Non si divide … appena afferra il file eseguibile.
  12. 0

    (leggendo la tua domanda, appena prima di postare faccio notare tu dici riga di comando COME stringa, quindi questa informazione non può essere utile a voi, ma come ho scritto io il post in ogni caso – si prega di ignorare se ho missunderstood domanda).

    Se è chiarire la tua domanda cercherò di aiutare, ma in generale i commenti che ti hanno fatto direi di non farlo :-), si sta chiedendo per una regexp per dividere una serie di parmeters in un array. Invece di fare questo da soli vorrei consiglia di considerare l’utilizzo di getopt, ci sono le versioni di questa libreria per la maggior parte dei linguaggi di programmazione. Getopt fare quello che stai chiedendo e scale di gestire molto più sofisticato argomento di elaborazione dovrebbe avete bisogno in futuro.

    Se mi fate sapere in che linguaggio stai usando cerchero ‘ di postare un esempio per voi.

    Ecco un esempio di home page:

    http://www.codeplex.com/getopt
    (.NET)

    http://www.urbanophile.com/arenn/hacking/download.html
    (java)

    Un campione (da java pagina di cui sopra)

     Getopt g = new Getopt("testprog", argv, "ab:c::d");
     //
     int c;
     String arg;
     while ((c = g.getopt()) != -1)
       {
         switch(c)
           {
              case 'a':
              case 'd':
                System.out.print("You picked " + (char)c + "\n");
                break;
                //
              case 'b':
              case 'c':
                arg = g.getOptarg();
                System.out.print("You picked " + (char)c + 
                                 " with an argument of " +
                                 ((arg != null) ? arg : "null") + "\n");
                break;
                //
              case '?':
                break; //getopt() already printed an error
                //
              default:
                System.out.print("getopt() returned " + c + "\n");
           }
       }

Lascia un commento