Разбор текста с разделителями с помощью escape-символов - PullRequest
2 голосов
/ 12 февраля 2010

Я пытаюсь разобрать (в Ruby), что фактически представляет собой файл формата passwd в UNIX: разделители-запятые с escape-символом \, так что все, что экранировано, должно рассматриваться буквально. Я пытаюсь использовать для этого регулярное выражение, но у меня ничего не получится - даже при использовании Oniguruma для утверждений «lookahead / lookbehind».

По сути, все следующее должно работать:

a,b,c    # => ["a", "b", "c"]
\a,b\,c  # => ["a", "b,c"]
a,b,c\
d        # => ["a", "b", "c\nd"]
a,b\\\,c # => ["a", "b\,c"]

Есть идеи?

Первый ответ выглядит довольно хорошо. С файлом, содержащим

\a,,b\\\,c\,d,e\\f,\\,\
g

это дает:

[["\\a,"], [","], ["b\\\\\\,c\\,d,"], ["e\\\\f,"], ["\\\\,"], ["\\\ng\n"], [""]]

что довольно близко. Мне не нужно делать экскаватор на этом первом проходе, если все разделено на запятые. Я попробовал Oniguruma и закончил с (гораздо дольше):

Oniguruma::ORegexp.new(%{
  (?:       # - begins with (but doesn't capture)
    (?<=\A) #   - start of line
    |       #   - (or) 
    (?<=,)  #   - a comma
  )

  (?:           # - contains (but doesn't capture)
    .*?         #   - any set of characters
    [^\\\\]?    #   - not ending in a slash
    (\\\\\\\\)* #   - followed by an even number of slashes
  )*?

  (?:      # - ends with (but doesn't capture)
    (?=\Z) #   - end of line
    |      #   - (or)
    (?=,)) #   - a comma
  },

  'mx'
).scan(s)

Ответы [ 2 ]

3 голосов
/ 13 февраля 2010

Попробуйте это:

s.scan(/((?:\\.|[^,])*,?)/m)

Он не переводит символы, следующие за \, но впоследствии это можно сделать как отдельный шаг.

2 голосов
/ 12 февраля 2010

Я бы попробовал класс CSV .

И решение регулярных выражений (хак?) Может выглядеть так:

#!/usr/bin/ruby -w

# contents of test.csv:
#   a,b,c
#   \a,b\,c
#   a,b,c\
#   d
#   a,b\\\,c

file = File.new("test.csv", "r")
tokens = file.read.scan(/(?:\\.|[^,\r\n])*|\r?\n/m)
puts "-----------"
tokens.length.times do |i|
  if tokens[i] == "\n" or tokens[i] == "\r\n"
    puts "-----------"
  else
    puts ">" + tokens[i] + "<"
  end
end
file.close

, который выдаст результат:

-----------
>a<
>b<
>c<
-----------
>\a<
>b\,c<
-----------
>a<
>b<
>c\
d<
-----------
>a<
>b\\\,c<
-----------
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...