Удаление обратной косой черты (escape-символ) из строки

Я пытаюсь работать над своим парсером JSON. У меня есть строка ввода, которую я хочу tokenize:

input = "{ \"foo\": \"bar\", \"num\": 3}"

Как удалить escape-символ \, чтобы он не был частью моих токенов?

В настоящее время мое решение с использованием delete работает:

tokens = input.delete('\\"').split("")

=> ["{", " ", "f", "o", "o", ":", " ", "b", "a", "r", ",", " ", "n", "u", "m", ":", " ", "3", "}"]

Однако, когда я пытаюсь использовать gsub, он не может найти какой-либо \".

tokens = input.gsub('\\"', '').split("")

=> ["{", " ", "\"", "f", "o", "o", "\"", ":", " ", "\"", "b", "a", "r", "\"", ",", " ", "\"", "n", "u", "m", "\"", ":", " ", "3", "}"]

У меня есть два вопроса:

1. Почему gsub не работает в этом случае?

2. Как удалить символ обратной косой черты (escape)? В настоящее время я должен удалить символ обратной косой черты с помощью кавычек, чтобы сделать эту работу.

Ответ 1

Когда вы пишете:

input = "{ \"foo\": \"bar\", \"num\": 3}"

Фактическая строка, хранящаяся на входе:

{ "foo": "bar", "num": 3}

Вывод \" здесь интерпретируется синтаксическим анализатором Ruby, так что он может различать границу строки (наиболее левую и правую большую ") и нормальный символ " в строке ( беглые).

String#delete удаляет набор символов, указанный первым параметром, а не шаблоном. Все символы, которые находятся в первом параметре, будут удалены. Итак, написав

input.delete('\\"')

У вас есть строка со всеми \ и " удалена из input, а не строка со всей последовательностью \", удаленной из input. Это неверно для вашего дела. Это может вызвать неожиданное поведение спустя некоторое время.

String#gsub, однако, замените шаблон (либо регулярное выражение, либо обычную строку).

input.gsub('\\"', '')

означает найти все \" (два символа в последовательности) и заменить их пустой строкой. Поскольку в input нет \, ничего не заменилось. На самом деле вам нужно:

input.gsub('"', '')

Ответ 2

У вас нет обратной косой черты в вашей строке. У вас есть кавычки в вашей строке, которые должны быть экранированы при размещении в строке с двумя кавычками. Посмотрите:

input = "{ \"foo\": \"bar\", \"num\": 3}"
puts input
# => { "foo": "bar", "num": 3}

Вы удаляете - фантомы.

input.delete('\\"')

удалит любые символы в своем аргументе. Таким образом, вы удаляете любые несуществующие обратные слэши, а также удаляете все кавычки. Без кавычек метод отображения по умолчанию (inspect) не нуждается ни в чем.

input.gsub('\\"', '')

попытается удалить последовательность \", которая не существует, поэтому gsub ничего не делает.

Убедитесь, что вы знаете, какая разница между строковым представлением (puts input.inspect) и содержимым строки (puts input), и обратите внимание на обратную косую черту как на артефакты представления.

Тем не менее, я должен повторить эмаиленин: писать правильный парсер JSON непросто, и вы не можете делать это с помощью регулярных выражений (или, по крайней мере, не с регулярными регулярными выражениями, возможно, с Oniguruma). Он нуждается в правильном парсере, таком как treetop или rex/racc, поскольку у него много угловых случаев, которые легко пропустить (главными из них являются, по иронии судьбы, экранированные персонажи).

Ответ 3

Использовать шаблон регулярного выражения:

> input = "{ \"foo\": \"bar\", \"num\": 3}"
> input.gsub(/"/,'').split("")

> => ["{", " ", "f", "o", "o", ":", " ", "b", "a", "r", ",", " ", "n", "u", "m", ":", " ", "3", "}"]

Это фактически двойная кавычка. Слэш должен убежать от него.

Ответ 4

input.gsub(/[\"]/,"") также будет работать.