Токенизировать строку в кавычках - PullRequest
3 голосов
/ 01 августа 2011

Я пытаюсь токенизировать строки. Пока нет символов цитирования, все в порядке:

string:tokens ("abc def ghi", " ").
["abc","def","ghi"]

Но string: tokens / 2 очень мне помогает со строками в кавычках. Он ведет себя как ожидалось:

string:tokens ("abc \"def xyz\" ghi", " ").
["abc","\"def","xyz\"","ghi"]

Что мне нужно, так это функция, которая принимает строку для токенизации, разделитель и символ кавычки. Что-то вроде:

tokens ("abc \"def xyz\" ghi", " ", "\"").
["abc","def xyz","ghi"]

Теперь, прежде чем я начну изобретать велосипед, мой вопрос:

Есть ли такая функция или подобная в стандартных библиотеках?

EDIT:

Хорошо, я написал свою собственную реализацию, но я все еще очень заинтересован в ответах на оригинальный вопрос. Вот мой код:

tokens (String) -> tokens (String, [], [] ).

tokens ( [], Tokens, Buffer) ->
    lists:map (fun (Token) -> string:strip (Token, both, $") end, Tokens ++ [Buffer] );

tokens ( [Character | String], Tokens, Buffer) ->
    case {Character, Buffer} of
        {$ , [] } -> tokens (String, Tokens, Buffer);
        {$ , [$" | _] } -> tokens (String, Tokens, Buffer ++ [Character] );
        {$ , _} -> tokens (String, Tokens ++ [Buffer], [] );
        {$", [] } -> tokens (String, Tokens, "\"" );
        {$", [$" | _] } -> tokens (String, Tokens ++ [Buffer ++ "\""], [] );
        {$", _} -> tokens (String, Tokens ++ [Buffer], "\"");
        _ -> tokens (String, Tokens, Buffer ++ [Character] )
    end.

Ответы [ 4 ]

5 голосов
/ 01 августа 2011

Если в общем случае допустимы регулярные выражения, вы можете использовать:

> re:split("abc \"def xyz\" ghi", " \"|\" ", [{return, list}]).
["abc","def xyz","ghi"]

Вы также можете использовать "\s\"|\"\s", если хотите разделить на основе любого пробела, а не только пробелов.

Если вы анализируете это из входного файла, вы можете использовать strip_split/2 из estring .

2 голосов
/ 02 августа 2011

string:tokens ("abc \"def ghi\" foo.bla", " .\""). помечает строку на пробел, точку и двойные кавычки.Результат: ["abc", "def", "ghi", "foo", "bla"].Если вы хотите сохранить процитированные части, вы можете подумать о создании токена / лексера, потому что регулярное выражение не очень хорошо в этой работе.

1 голос
/ 02 августа 2011

Примерно так бы и написал (не проверял!):

tokens(String) -> lists:reverse(tokens(String, outside_quotes, [])).

tokens([], outside_quotes, Tokens) ->
  Tokens;
tokens(String, outside_quotes, Tokens) -> 
  {Token, Rest0} = lists:splitwith(fun(C) -> (C != $ ) and (С != $"), String),
  case Rest0 of 
    [] -> [Token | Tokens];
    [$  | Rest] -> tokens(Rest, outside_quotes, [Token | Tokens]);
    [$" | Rest] -> tokens(Rest, inside_quotes, [Token | Tokens])
  end;
tokens(String, inside_quotes, Tokens) -> 
  %% exception on an unclosed quote
  {Token, [$" | Rest]} = lists:splitwith(fun(C) -> С != $", String),
  tokens(Rest, outside_quotes, [Token | Tokens]).
1 голос
/ 01 августа 2011

Вы можете использовать модуль re .Он поставляется с функцией split/3.Например:

re:split("abc \"def xyz \"ghi", "[(\s\")\s\"]", [{return, list}]).
["abc",[],"def","xyz",[],"ghi"]

Второй аргумент является регулярным выражением (возможно, вам придется настроить мой пример для удаления пустых списков ...)

...