2010-11-24 36 views

回答

11

好吧,如果你不喜歡eval的解決方案,我已經入侵了一個簡單的狀態機在Ruby中的字符串正確地分析簡單的「\ n」和「\ t」的,包括預-E反斜槓本身的縮放。那就是:

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

短,更哈克和相當危險的,因爲EVAL:

eval "\"#{string}\""
一個簡單的例子:
 
> a = '1\t2\n3' 
> puts a 
1\t2\n3 
> puts eval "\"#{a}\"" 
1  2 
3 

+0

是,已經發生,我認爲......但EVAL是邪惡:-) – Simon 2010-11-24 12:43:22

0

編輯:請注意,這實際上並沒有正常工作。你真的需要在這裏用狀態機構建一個合適的分析器來跟蹤你是否處於轉義序列中。


Ruby支持許多相同的轉義序列,所以你可以建立一個簡單的翻譯表是這樣的:

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" 
+4

它不會工作,要麼;解析「\ n」構造有點困難,只是搜索和替換 - 你必須首先注意逃逸序列的逃逸。事實上,只需逐字節地執行一行就可以輕鬆完成。 – GreyCat 2010-11-24 17:03:51