DISABILITARE ADBLOCK

ADBlock sta bloccando alcuni contenuti del sito

ADBlock errore
risultati trovati: 

DOMANDA

Data una stringa come questa:

  

a, " string, con ", vari valori " e alcuni ", quotati

Qual è un buon algoritmo per dividerlo in base alle virgole ignorando le virgole all'interno delle sezioni tra virgolette?

L'output dovrebbe essere un array:

  

["quot" a "quot", "quot" stringa, con "quot", "quot" vari "quot", "quot" valori e alcuni "quot", "quot" " ]

SOLUZIONE

Se la mia lingua preferita non offrisse un modo per farlo senza pensarci, inizialmente prenderei in considerazione due opzioni come via d'uscita:

  1. Pre-analizza e sostituisci le virgole all'interno della stringa con un altro carattere di controllo, quindi dividile, seguito da un post-analisi sull'array per sostituire il carattere di controllo utilizzato in precedenza con le virgole.

  2. In alternativa, dividerli sulle virgole quindi post-analizzare l'array risultante in un altro array controllando le virgolette iniziali su ciascuna voce dell'array e concatenando le voci fino a quando non ho raggiunto una virgoletta finale.

Questi sono comunque degli hack e, se si tratta di un puro esercizio "mentale", sospetto che si dimostreranno inutili. Se questo è un problema del mondo reale, sarebbe utile conoscere la lingua in modo da poter offrire alcuni consigli specifici.

Se ti va lasciaci una tua opinione

L'articolo ti è stato utile ed è tradotto correttamente?

ALTRI SUGGERIMENTI

Sembra che tu abbia delle buone risposte qui.

Per quelli di voi che desiderano gestire il proprio analisi dei file CSV, seguire i consigli degli esperti e Non eseguire il roll il tuo parser CSV .

Il tuo primo pensiero è " Devo gestire le virgole all'interno delle virgolette. "

Il tuo prossimo pensiero sarà, " Oh, merda, ho bisogno di gestire le virgolette all'interno delle virgolette. Citazioni di escape. Virgolette. Virgolette singole ... "

È una strada per la follia. Non scrivere il tuo. Trova una libreria con un'ampia copertura di test unitari che colpisca tutte le parti difficili e abbia attraversato l'inferno per te. Per .NET, usa la libreria FileHelpers gratuita.

Python:

import csv
reader = csv.reader(open("some.csv"))
for row in reader:
    print row

Ovviamente usare un parser CSV è meglio, ma solo per divertirti puoi:

Loop on the string letter by letter.
    If current_letter == quote : 
        toggle inside_quote variable.
    Else if (current_letter ==comma and not inside_quote) : 
        push current_word into array and clear current_word.
    Else 
        append the current_letter to current_word
When the loop is done push the current_word into array 

L'autore qui è caduto in un blob di codice C # che gestisce lo scenario con cui stai riscontrando problemi:

Importazioni di file CSV in .Net

Non dovrebbe essere troppo difficile da tradurre.

  

Cosa succede se viene visualizzato un numero dispari di virgolette   nella stringa originale?

Questo assomiglia in modo inequivocabile all'analisi CSV, che presenta alcune peculiarità nella gestione dei campi tra virgolette. Il campo viene escluso solo se il campo è delimitato da virgolette doppie, quindi:

  

field1, "field2, field3", field4, "field5, field6" field7

diventa

  

campo1

     

field2, field3

     

Campo4

     

" field5

     

field6 " field7

Nota se non inizia e termina con una citazione, quindi non è un campo tra virgolette e le doppie virgolette vengono semplicemente trattate come doppie virgolette.

Inavvertitamente il mio codice a cui qualcuno è collegato in realtà non lo gestisce correttamente, se ricordo bene.

Ecco una semplice implementazione di Python basata sullo pseudocodice di Pat:

def splitIgnoringSingleQuote(string, split_char, remove_quotes=False):
    string_split = []
    current_word = ""
    inside_quote = False
    for letter in string:
      if letter == "'":
        if not remove_quotes:
           current_word += letter
        if inside_quote:
          inside_quote = False
        else:
          inside_quote = True
      elif letter == split_char and not inside_quote:
        string_split.append(current_word)
        current_word = ""
      else:
        current_word += letter
    string_split.append(current_word)
    return string_split

Lo uso per analizzare le stringhe, non sono sicuro che sia utile qui; ma con qualche piccola modifica forse?

function getstringbetween($string, $start, $end){
    $string = " ".$string;
    $ini = strpos($string,$start);
    if ($ini == 0) return "";
    $ini += strlen($start);   
    $len = strpos($string,$end,$ini) - $ini;
    return substr($string,$ini,$len);
}

$fullstring = "this is my [tag]dog[/tag]";
$parsed = getstringbetween($fullstring, "[tag]", "[/tag]");

echo $parsed; // (result = dog) 

/ mp

Questa è un'analisi standard in stile CSV. Molte persone cercano di farlo con espressioni regolari. Puoi ottenere circa il 90% con regex, ma hai davvero bisogno di un vero parser CSV per farlo correttamente. Ho trovato un veloce, eccellente parser C # CSV su CodeProject che alcuni mesi fa Consiglio vivamente!

Eccone uno in pseudocodice (a.k.a. Python) in un passaggio :-P

def parsecsv(instr):
    i = 0
    j = 0

    outstrs = []

    # i is fixed until a match occurs, then it advances
    # up to j. j inches forward each time through:

    while i < len(instr):

        if j < len(instr) and instr[j] == '"':
            # skip the opening quote...
            j += 1
            # then iterate until we find a closing quote.
            while instr[j] != '"':
                j += 1
                if j == len(instr):
                    raise Exception("Unmatched double quote at end of input.")

        if j == len(instr) or instr[j] == ',':
            s = instr[i:j]  # get the substring we've found
            s = s.strip()    # remove extra whitespace

            # remove surrounding quotes if they're there
            if len(s) > 2 and s[0] == '"' and s[-1] == '"':
                s = s[1:-1]

            # add it to the result
            outstrs.append(s)

            # skip over the comma, move i up (to where
            # j will be at the end of the iteration)
            i = j+1

        j = j+1

    return outstrs

def testcase(instr, expected):
    outstr = parsecsv(instr)
    print outstr
    assert expected == outstr

# Doesn't handle things like '1, 2, "a, b, c" d, 2' or
# escaped quotes, but those can be added pretty easily.

testcase('a, b, "1, 2, 3", c', ['a', 'b', '1, 2, 3', 'c'])
testcase('a,b,"1, 2, 3" , c', ['a', 'b', '1, 2, 3', 'c'])

# odd number of quotes gives a "unmatched quote" exception
#testcase('a,b,"1, 2, 3" , "c', ['a', 'b', '1, 2, 3', 'c'])

Ecco un semplice algoritmo:

  1. Determina se la stringa inizia con un carattere '"'
  2. Dividi la stringa in un array delimitato dal carattere '"' .
  3. Contrassegna le virgolette con un segnaposto # COMMA #
    • Se l'input inizia con un '"' , contrassegnare quegli elementi dell'array in cui l'indice% 2 == 0
    • In caso contrario, contrassegnare quegli elementi nella matrice in cui l'indice% 2 == 1
  4. Concatena gli elementi nell'array per formare una stringa di input modificata.
  5. Dividi la stringa in un array delimitato dal carattere ',' .
  6. Sostituisci tutte le istanze nell'array di segnaposto # COMMA # con il carattere ',' .
  7. L'array è il tuo output.

Ecco l'implementazione di Python:
(risolto per gestire "" a, b ", c,", d, e, f, h ",", i, j, k "")

def parse_input(input):

    quote_mod = int(not input.startswith('"'))

    input = input.split('"')
    for item in input:
        if item == '':
            input.remove(item)
    for i in range(len(input)):
        if i % 2 == quoted_mod:
            input[i] = input[i].replace(",", "#COMMA#")

    input = "".join(input).split(",")
    for item in input:
        if item == '':
            input.remove(item)
    for i in range(len(input)):
        input[i] = input[i].replace("#COMMA#", ",")
    return input

# parse_input('a,"string, with",various,"values, and some",quoted')
#  -> ['a,string', ' with,various,values', ' and some,quoted']
# parse_input('"a,b",c,"d,e,f,h","i,j,k"')
#  -> ['a,b', 'c', 'd,e,f,h', 'i,j,k']

Non riuscivo proprio a resistere nel vedere se potevo farlo funzionare in un one-liner Python:

arr = [i.replace("|", ",") for i in re.sub('"([^"]*)\,([^"]*)"',"\g<1>|\g<2>", str_to_test).split(",")]

Restituisce ['a', 'stringa, con', 'vari', 'valori e alcuni', 'quoted']

Funziona sostituendo prima le virgolette ',' all'interno di un altro separatore (|), suddividere la stringa in "," e sostituire | di nuovo separatore.

Dato che hai detto il linguaggio agnostico, ho scritto il mio algoritmo nella lingua più vicina allo pseudocodice come possibile:

def find_character_indices(s, ch):
    return [i for i, ltr in enumerate(s) if ltr == ch]


def split_text_preserving_quotes(content, include_quotes=False):
    quote_indices = find_character_indices(content, '"')

    output = content[:quote_indices[0]].split()

    for i in range(1, len(quote_indices)):
        if i % 2 == 1: # end of quoted sequence
            start = quote_indices[i - 1]
            end = quote_indices[i] + 1
            output.extend([content[start:end]])

        else:
            start = quote_indices[i - 1] + 1
            end = quote_indices[i]
            split_section = content[start:end].split()
            output.extend(split_section)

        output += content[quote_indices[-1] + 1:].split()                                                                 

    return output

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow