Skip to content

Instantly share code, notes, and snippets.

@abulte
Created October 3, 2018 15:51

Revisions

  1. abulte created this gist Oct 3, 2018.
    89 changes: 89 additions & 0 deletions python-csv-fail-parsing-csv-doublequote.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,89 @@
    import re

    def _guess_quote_and_delimiter(data, delimiters=None):
    """
    Looks for text enclosed between two identical quotes
    (the probable quotechar) which are preceded and followed
    by the same character (the probable delimiter).
    For example:
    ,'some text',
    The quote with the most wins, same with the delimiter.
    If there is no quotechar the delimiter can't be determined
    this way.
    """

    matches = []
    for restr in (r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?P=delim)', # ,".*?",
    r'(?:^|\n)(?P<quote>["\']).*?(?P=quote)(?P<delim>[^\w\n"\'])(?P<space> ?)', # ".*?",
    r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?:$|\n)', # ,".*?"
    r'(?:^|\n)(?P<quote>["\']).*?(?P=quote)(?:$|\n)'): # ".*?" (no delim, no space)
    regexp = re.compile(restr, re.DOTALL | re.MULTILINE)
    matches = regexp.findall(data)
    if matches:
    break

    if not matches:
    # (quotechar, doublequote, delimiter, skipinitialspace)
    return ('', False, None, 0)
    quotes = {}
    delims = {}
    spaces = 0
    groupindex = regexp.groupindex
    for m in matches:
    n = groupindex['quote'] - 1
    key = m[n]
    if key:
    quotes[key] = quotes.get(key, 0) + 1
    try:
    n = groupindex['delim'] - 1
    key = m[n]
    except KeyError:
    continue
    if key and (delimiters is None or key in delimiters):
    delims[key] = delims.get(key, 0) + 1
    try:
    n = groupindex['space'] - 1
    except KeyError:
    continue
    if m[n]:
    spaces += 1

    quotechar = max(quotes, key=quotes.get)

    if delims:
    delim = max(delims, key=delims.get)
    skipinitialspace = delims[delim] == spaces
    if delim == '\n': # most likely a file with a single column
    delim = ''
    else:
    # there is *no* delimiter, it's a single column of quoted data
    delim = ''
    skipinitialspace = 0

    # if we see an extra quote between delimiters, we've got a
    # double quoted format
    dq_regexp = re.compile(
    r"((%(delim)s)|^)\W*%(quote)s[^%(delim)s\n]*%(quote)s[^%(delim)s\n]*%(quote)s\W*((%(delim)s)|$)" % \
    {'delim':re.escape(delim), 'quote':quotechar}, re.MULTILINE)

    if dq_regexp.search(data):
    doublequote = True
    else:
    doublequote = False

    return (quotechar, doublequote, delim, skipinitialspace)

    data = """"Numéro de dossier","Administration","Type","Année","Séance","Objet","Thème et sous thème","Mots clés","Sens et motivation","Partie","Avis"
    "20180364","Préfecture de la Haute-Vienne","Avis","2018","17/05/2018","communication des listes électorales en vue de l'organisation d'une cousinade.","Vie publique / Elections politiques","Liste électorale","Favorable","III","Madame X a saisi la commission d'accès aux documents administratifs, par un courrier enregistré à son secrétariat le 24 janvier 2018, du refus opposé par la préfecture de la Haute-Vienne à sa demande de communication des listes électorales du département.
    Après avoir pris connaissance de la réponse de l'administration, la commission rappelle que la communication intégrale des listes électorales est régie par les dispositions particulières des articles L28 et R16 du code électoral, qui prévoient que ces listes sont communicables à tout candidat, parti ou groupement politique ainsi qu’à tout électeur, quel que soit le lieu où il est inscrit. L’article R16 de ce code précise que la communication à un électeur est subordonnée à la condition qu’il s’engage à ne pas en faire un usage purement commercial.
    Dans sa décision du 2 décembre 2016 n° 388979 (au recueil), le Conseil d'Etat a jugé qu'afin d'éviter toute exploitation commerciale des données personnelles que comporte une liste électorale, le pouvoir réglementaire a subordonné l'exercice du droit d'accès à l'engagement, de la part du demandeur, de ne pas en faire un usage commercial. S'il existe, au vu des éléments dont elle dispose et nonobstant l'engagement pris par le demandeur, des raisons sérieuses de penser que l'usage des listes électorales risque de revêtir, en tout ou partie, un caractère commercial, l'autorité compétente peut rejeter la demande de communication de la ou des listes électorales dont elle est saisie. Il lui est loisible de solliciter du demandeur qu'il produise tout élément d'information de nature à lui permettre de s'assurer de la sincérité de son engagement de ne faire de la liste électorale qu'un usage conforme aux dispositions des articles L28 et R16 du code électoral. L'absence de réponse à une telle demande peut être prise en compte parmi d'autres éléments, par l'autorité compétente afin d'apprécier, sous le contrôle du juge, les suites qu'il convient de réserver à la demande dont elle est saisie.
    La commission considère que le caractère purement commercial ou non de l’usage des listes s’apprécie au regard de l’objet de la réutilisation envisagée et de l’activité dans laquelle elle s’inscrit, la forme juridique retenue par le ré-utilisateur pour poursuivre cette activité et l'existence ou l'absence de ressources tirées de cet usage constituant à cet égard de simples indices. Doivent être regardées comme purement commerciales non seulement la commercialisation des données elles-mêmes, le cas échéant après retraitement, mais aussi leur utilisation dans le cadre d’une activité à but lucratif.
    En l'espèce, la commission constate que Madame X certifie ne pas formuler sa demande dans un but commercial et mentionne l'objectif d'organiser une réunion de famille, dite ""cousinade"". La commission considère qu'en l'état, il n'existe aucun indice qui permettrait de penser que l'usage de ces listes électorales risquerait de revêtir, en tout ou partie, un caractère commercial, même si l'intéressée n'a pas souhaité communiquer le nom de la personne hébergée en EHPAD au profit de laquelle l'évènement est organisé. La commission émet donc un avis favorable à la demande, sous réserve que Madame X justifie de sa qualité d'électeur, quel que soit le lieu où elle est inscrite."
    """

    # second item should be True
    _guess_quote_and_delimiter(data)