Как убрать escape-последовательности в стиле c из ruby? - PullRequest
6 голосов
/ 24 ноября 2010

В ruby, как мне декодировать escape-последовательности в стиле c?например, \ n для новой строки, \ t для вкладки?

Ответы [ 3 ]

11 голосов
/ 24 ноября 2010

Хорошо, если вам не нравится решение eval, я взломал простой конечный автомат в Ruby, чтобы правильно проанализировать простые строки "\ n" и "\ t" в строках, включая предварительное экранирование самого обратного слэша. Вот оно:

BACKSLASH = "\\"

def unescape_c_string(s)
    state = 0
    res = ''
    s.each_char { |c|
        case state
        when 0
            case c
            when BACKSLASH then state = 1
            else res << c
            end
        when 1
            case c
            when 'n' then res << "\n"; state = 0
            when 't' then res << "\t"; state = 0
            when BACKSLASH then res << BACKSLASH; state = 0
            else res << BACKSLASH; res << c; state = 0
            end
        end
    }
    return res
end

Этот можно легко расширить для поддержки большего количества символов, включая многосимвольные объекты, такие как \123. Тестовый блок, чтобы доказать, что он работает:

require 'test/unit'

class TestEscapeCString < Test::Unit::TestCase
    def test_1
        assert_equal("abc\nasd", unescape_c_string('abc\nasd'))
    end
    def test_2
        assert_equal("abc\tasd", unescape_c_string('abc\tasd'))
    end
    def test_3
        assert_equal("abc\\asd", unescape_c_string('abc' + BACKSLASH * 2 + 'asd'))
    end
    def test_4
        assert_equal("abc\\nasd", unescape_c_string('abc' + BACKSLASH * 2 + 'nasd'))
    end
    def test_5
        assert_equal("abc\\\nasd", unescape_c_string('abc' + BACKSLASH * 3 + 'nasd'))
    end
    def test_6
        assert_equal("abc\\\\nasd", unescape_c_string('abc' + BACKSLASH * 4 + 'nasd'))
    end
end
3 голосов
/ 24 ноября 2010

Короче, еще более хакерский и довольно опасный из-за eval: eval "\"#{string}\"" Простой пример: > a = '1\t2\n3' > puts a 1\t2\n3 > puts eval "\"#{a}\"" 1 2 3

0 голосов
/ 24 ноября 2010

РЕДАКТИРОВАТЬ: Обратите внимание, что это на самом деле не работает. Вам действительно нужно создать правильный синтаксический анализатор с конечным автоматом, который отслеживает, находитесь ли вы в escape-последовательности или нет.


Ruby поддерживает множество одинаковых escape-последовательностей, поэтому вы можете создать простую таблицу перевода, например:

T = {
  '\n' => "\n",
  '\t' => "\t",
  '\r' => "\r"
}

А затем используйте эту таблицу перевода для замены этих последовательностей в исходной строке:

a = '1\t2\n3'

a.gsub(/#{T.keys.map(&Regexp.method(:escape)).join('|')}/, &T.method(:[]))
# => "1\t2\n3"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...