Vra

Gegewe'n string soos hierdie:

'n,"string, met",verskeie,"waardes, en'n paar",aangehaal

Wat is'n goeie algoritme te verdeel hierdie gebaseer op kommas terwyl ignoreer die kommas in die aangehaalde gedeeltes?

Die uitset moet word om'n verskeidenheid:

[ "'n", "string, met", "verskillende", "waardes, en'n paar", "aangehaal" ]

Was dit nuttig?

Oplossing

As my taal van keuse nie 'n manier om dit te doen sonder om te dink, dan sou ek aanvanklik oorweeg twee opsies as die maklike uitweg kon aanbied:

  1. Pre-parse en die kommas binne die string met 'n ander beheer karakter vervang dan verdeel hulle, gevolg deur 'n post-ontleed op die skikking na die beheer karakter wat voorheen gebruik is met die kommas vervang.

  2. Alternatiewelik verdeel hulle op die kommas dan post-ontleed die gevolglike skikking in 'n ander verskeidenheid nagaan vir die leiding van aanhalings op elke verskeidenheid inskrywing en concatenating die inskrywings totdat ek 'n tydelike quote bereik.

Dit is hacks egter en as dit 'n suiwer 'n geestelike "oefening dan vermoed ek hulle sal help nie bewys. As dit is 'n werklike wêreld probleem dan is dit sal help om die taal ken, sodat ons 'n paar spesifieke advies kan bied.

Ander wenke

Dit lyk of jy 'n paar goeie antwoorde hier het.

Vir dié van julle op soek na jou eie CSV parsing hanteer, ag slaan op die raad van die kenners en Moenie rol jou eie CSV parser .

Jou eerste gedagte is, "Ek moet kommas hanteer binnekant van aanhalings."

Jou volgende gedagte sal wees, "O, kak, ek moet aanhalings hanteer binnekant van aanhalings. Ontsnap aanhalings. Dubbele aanhalingstekens. Enkelaanhalingstekens ..."

Dit is 'n pad tot waansin. Moenie skryf jou eie. Vind 'n biblioteek met 'n uitgebreide eenheid toets dekking wat al die harde dele treffers en het gegaan deur die hel vir jou. Vir NET, gebruik die gratis FileHelpers biblioteek.

Python:

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

Natuurlik met behulp van 'n CSV parser is beter, maar net vir die pret daarvan jy kan:

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 

Die skrywer hier in 'n blob van C # kode wat die scenario wat jy met 'n probleem met handvatsels gedaal:

CSV invoer in Net

Moet nie te moeilik om te vertaal.

  

Wat gebeur as 'n onewe aantal aanhalings verskyn   in die oorspronklike string?

Dit lyk ongewone soos CSV parsing, wat 'n paar eienaardighede te hanteer aangehaal velde het. Die veld is net ontsnap as die veld is afgebaken met 'n dubbele aanhalings, so:

  

veld1, "veld2, veld3", veld4, "field5, field6" field7

raak

  

veld1

     

veld2, veld3

     

veld4

     

"field5

     

field6 "field7

Let as dit nie beide begin en eindig met 'n kwotasie, dan is dit nie 'n aangehaal veld en die dubbele aanhalingstekens is eenvoudig beskou as dubbele aanhalingstekens.

Insedently my kode wat iemand wat verband hou met nie eintlik hierdie reg te hanteer, as ek reg onthou.

Hier is 'n eenvoudige luislang implementering gebaseer op pseudokode Pat se:

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

Ek gebruik dit om stringe te ontleed, nie seker of dit hier help; maar met 'n paar klein veranderinge miskien?

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) 

/ LP

Dit is 'n standaard CSV-styl parse. Baie mense probeer om dit te doen met gereelde uitdrukkings. Jy kan tot sowat 90% te kry met regexes, maar jy regtig nodig het 'n ware CSV parser om dit behoorlik te doen. Ek het gevind dat 'n vinnig, 'n uitstekende C # CSV parser op CodeProject 'n paar maande gelede wat Ek raai!

Hier is een in pseudokode (ook bekend as Python) in 'n keer :-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'])

Hier is 'n eenvoudige algoritme:

  1. bepaal of die string begin met 'n '"' karakter
  2. Verdeel die string in 'n skikking afgebaken deur die '"' karakter.
  3. Merk die gekwoteer kommas met 'n plekhouer #COMMA#
    • As die insette begin met 'n '"', merk die items in die skikking waar die indeks% 2 == 0
    • Anders merk die items in die skikking waar die indeks% 2 == 1
  4. koppel die items in die skikking na 'n gemodifiseerde insette string te vorm.
  5. Verdeel die string in 'n skikking afgebaken deur die ',' karakter.
  6. Vervang alle gevalle in die skikking van #COMMA# plekhouers met die ',' karakter.
  7. Die skikking is jou uitset.

Hier is die luislang implementering:
(Vaste om te hanteer "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']

Ek kon net nie die versoeking weerstaan om te sien as ek kon maak dit werk in'n Python een-liner:

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

Opbrengste ["a", 'string, met', 'verskeie', 'waardes, en'n paar', 'aangehaal']

Dit werk deur die eerste vervanging van die", " binne aanhalings na'n ander skeiding (|), die verdeling van die string op ',' en die vervanging van die | separator weer.

Omdat jy sê taal agnostikus, het ek my algoritme in die taal wat die naaste aan pseudokode as moontlik:

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
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top