<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DZone Snippets: quoted code</title>
    <link>http://snippets.dzone.com/posts</link>
    <pubDate>Sun, 18 May 2008 00:52:37 GMT</pubDate>
    <description>DZone Snippets: quoted code</description>
    <item>
      <title>Matching quoted strings in Ruby</title>
      <link>http://snippets.dzone.com/posts/show/5459</link>
      <description>An exercise in string processing and regexp matching, inspired by &lt;a href="http://mikenaberezny.com/2008/04/28/parsing-quoted-strings-in-ruby/"&gt;Parsing Quoted Strings in Ruby&lt;/a&gt; and &lt;a href="http://pivots.pivotallabs.com/users/nick/blog/articles/409-stupid-ruby-quoting-tricks/"&gt;Stupid Ruby Quoting Tricks&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;#!/usr/local/bin/ruby -w&lt;br /&gt;&lt;br /&gt;# some input examples&lt;br /&gt;str = 'foo "bar baz" qux'&lt;br /&gt;str = 'foo "bar baz " "bar baz" " bar baz" "bar "klr mre" " " \' "abc" \' baz " qux'&lt;br /&gt;str = '" \' \'    " \n "   " \' \' "" foo \'ttt sss\' "bar "qqq zzz" baz" "added term" qux  " \' \'    "  yyy xxx'&lt;br /&gt;str = '"""frickin \'#{bar}\'"""'&lt;br /&gt;str = '""    "frickin chicken "    #{bar}""""'&lt;br /&gt;str = '"""frickin "#{bar}""""'&lt;br /&gt;str = '"a "b c" "d "e" f g" """h""""'       # cf. http://snippets.dzone.com/posts/show/4852&lt;br /&gt;&lt;br /&gt;# escaped quotes&lt;br /&gt;str = '\"'&lt;br /&gt;str = "\\\""&lt;br /&gt;str = '\\\''&lt;br /&gt;str = "\\'"&lt;br /&gt;&lt;br /&gt;# special cases&lt;br /&gt;str = '"G","H I"'&lt;br /&gt;str = '"G","H I""G","H I"'&lt;br /&gt;&lt;br /&gt;str = '"abc""def"'&lt;br /&gt;str = '"""a""b"'&lt;br /&gt;str = '"abc""def""abc""def""abc""def"'&lt;br /&gt;str = '"a"\'\'"b"'&lt;br /&gt;&lt;br /&gt;str = "\"abc'vv'tt\"'klt'"&lt;br /&gt;&lt;br /&gt;str = "abc,def,\"efg,hij\",klm,nop,\"qrstuv\",wxyz"&lt;br /&gt;str = "abc,def,\"efg,hij\",klm, 'nop, \"qrstuv\",wxyz,mmm '"&lt;br /&gt;str = "abc,def,\"efg,hij\",klm, \"nop, 'qrstuv',wxyz,mmm \""&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;puts&lt;br /&gt;puts "input string:  #{str}" &lt;br /&gt;puts "str.inspect :  #{str.inspect}" &lt;br /&gt;puts&lt;br /&gt;&lt;br /&gt;num_of_chars1 = str.count('a-zA-Z_0-9', "^\000ds")&lt;br /&gt;&lt;br /&gt;error_code = 0      # in case of a parsing error Shellwords will be used instead of regex1 &amp; regex2&lt;br /&gt;str2 = str.clone&lt;br /&gt;&lt;br /&gt;# encode escaped quotes&lt;br /&gt;str = str.gsub(/\\"|\\'/) { |m| m =~ /^\\"$/ ? "\000d\000" : "\000s\000" }&lt;br /&gt;&lt;br /&gt;dq_count = str.count('"')&lt;br /&gt;sq_count = str.count("'")&lt;br /&gt;&lt;br /&gt;if dq_count % 2 != 0 &amp;&amp; sq_count % 2 != 0&lt;br /&gt;   raise ArgumentError, "\e[1modd number of single &amp; double quotes\e[m in: #{str}\nsq_count: #{sq_count}\ndq_count: #{dq_count}\n"&lt;br /&gt;elsif dq_count % 2 != 0&lt;br /&gt;   raise ArgumentError, "\e[1modd number of double quotes\e[m in: #{str}\ndq_count: #{dq_count}\n"&lt;br /&gt;elsif sq_count % 2 != 0&lt;br /&gt;   raise ArgumentError, "\e[1modd number of single quotes\e[m in: #{str}\nsq_count: #{sq_count}\n"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# regex1 separates substrings that contain quotes from substrings that do not contain quotes&lt;br /&gt;regex1 = %r{[^"']+|["'].*?["'](?!.*["'])}m  &lt;br /&gt;&lt;br /&gt;# example&lt;br /&gt;#"abc 'quote1' pjk 'quote2' xyz".scan(regex1) { |m| puts m } &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;regex2 = %r{&lt;br /&gt;# experimental: special cases&lt;br /&gt;\s*["'][^"']+["'][[:punct:]]["'][^"']+["']|  # special case:  xxx "ab c","def g" yyy&lt;br /&gt;\s*["'][^"']+["']{2,}[^"']+["']|             # special case:  xxx "abc""def" yyy&lt;br /&gt;\s"[^"]+"|                                   # special case: xxx "abc 'def' ghi"&lt;br /&gt;\s'[^']+'|                                   # special case: xxx 'abc "def" ghi'&lt;br /&gt;\s*["']\S+["']|                              # special case: "abc'vv'tt"'klt'&lt;br /&gt;&lt;br /&gt;\s'\s|                       # xxx ' yyy&lt;br /&gt;\s"\s|                       # xxx " yyy&lt;br /&gt;\s''\s|                      # xxx '' yyy&lt;br /&gt;\s""\s|                      # xxx "" yyy&lt;br /&gt;\s'\s+'\s|                   # xxx '   ' yyy&lt;br /&gt;\s"\s+"\s|                   # xxx "   " yyy&lt;br /&gt;\s"\s[^"]+\s"\s|             # xxx " abc " yyy&lt;br /&gt;\s'\s[^']+\s'\s|             # xxx ' abc ' yyy&lt;br /&gt;\s["']["']+(?=[^"'\s])|      # :qoblock:  xxx "'""'abc yyy&lt;br /&gt;[^"'\s]["']["']+(?=\s)|      # :qcblock:  xxx abc"'""' yyy&lt;br /&gt;\s""+|                       # :dqoblock:  xxx """abc yyy&lt;br /&gt;\s''+|                       # :sqoblock:  xxx '''abc yyy&lt;br /&gt;[^"]""+|                     # :dqcblock:  xxx abc"" yyy&lt;br /&gt;[^']''+|                     # :sqcblock:  xxx abc'' yyy&lt;br /&gt;\s["'](?=[^"'\s])|           # :dqo or :sqo:  xxx "abc yyy  or  xxx 'abc yyy&lt;br /&gt;[^"'\s]["'](?=\s)|           # :dqc or :sqc:  xxx abc" yyy  or  xxx abc' yyy&lt;br /&gt;[^"']+[^"'\s](?=\s)          # no quotes at all&lt;br /&gt;}mx&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;=begin&lt;br /&gt;&lt;br /&gt;There are different kinds of quotes matched by regex2 below. They include:&lt;br /&gt;&lt;br /&gt;- :sqo (single quote open)&lt;br /&gt;- :sqc (single quote close)&lt;br /&gt;- :sqoblock (single quote open block)&lt;br /&gt;- :sqcblock (single quote close block)&lt;br /&gt;&lt;br /&gt;- :dqo (double quote open)&lt;br /&gt;- :dqc (double quote close)&lt;br /&gt;- :dqoblock (double quote open block)&lt;br /&gt;- :dqcblock (double quote close block)&lt;br /&gt;&lt;br /&gt;- :qoblock (quote open block)&lt;br /&gt;- :qcblock (quote close block)&lt;br /&gt;&lt;br /&gt;=end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ret = []&lt;br /&gt;&lt;br /&gt;str.scan(regex1) do |s| &lt;br /&gt;&lt;br /&gt;   if s !~ /\A["']/&lt;br /&gt;&lt;br /&gt;      #puts "s1: #{s}"&lt;br /&gt;      #puts "s1.inspect: #{s.inspect}"&lt;br /&gt;&lt;br /&gt;      s.split(/\s+/m).each { |t| ret &lt;&lt; t unless t.empty? }&lt;br /&gt;&lt;br /&gt;   else&lt;br /&gt;&lt;br /&gt;      #puts "s2: #{s}"&lt;br /&gt;      #puts "s2.inspect: #{s.inspect}"&lt;br /&gt;&lt;br /&gt;      open_quotes = 0&lt;br /&gt;      close_quotes = 0&lt;br /&gt;      ar = []&lt;br /&gt;&lt;br /&gt;      # add spaces to simplify regex2 matching&lt;br /&gt;      s = "\x20" &lt;&lt; s &lt;&lt; "\x20"    &lt;br /&gt;      s.gsub!(/\x20/, "\x20\x20")  &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;      s.scan(regex2) do |m|&lt;br /&gt;&lt;br /&gt;         # get the index of the quote&lt;br /&gt;         # + 1 for leading space or non-space&lt;br /&gt;         # $` is the prematch string&lt;br /&gt;&lt;br /&gt;         index = $`.length + 1 &lt;br /&gt;&lt;br /&gt;         post_match = $'  &lt;br /&gt;&lt;br /&gt;         #puts&lt;br /&gt;         #puts "index: #{index}"&lt;br /&gt;         #puts "m: #{m.inspect}"&lt;br /&gt;         #puts "m.length: #{m.length}"&lt;br /&gt;         #puts "open_quotes:  #{open_quotes}\nclose_quotes: #{close_quotes}"&lt;br /&gt;         #puts "ret: #{ret.inspect}"&lt;br /&gt;         #puts "ar: #{ar.inspect}"&lt;br /&gt;         #puts&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;         if m =~ /\A\s''\s\z/&lt;br /&gt;&lt;br /&gt;            next unless open_quotes == 0 &amp;&amp; close_quotes == 0&lt;br /&gt;            ret &lt;&lt; ''&lt;br /&gt;            next&lt;br /&gt;&lt;br /&gt;         elsif m =~ /\A\s""\s\z/&lt;br /&gt;&lt;br /&gt;            next unless open_quotes == 0 &amp;&amp; close_quotes == 0&lt;br /&gt;            ret &lt;&lt; ""&lt;br /&gt;            next&lt;br /&gt;&lt;br /&gt;         # example: xxx "ab c","def g" yyy&lt;br /&gt;         elsif open_quotes.zero? &amp;&amp; close_quotes.zero? &amp;&amp; m =~ /\A\s*["'][^"']+["'][[:punct:]]["'][^"']+["']\z/ &amp;&amp; m.count('"') % 2 == 0 &amp;&amp; m.count("'") % 2 == 0           &lt;br /&gt;&lt;br /&gt;            m = m.gsub(/\x20\x20/, "\x20")&lt;br /&gt;            # cf. http://henrik.nyh.se/2008/03/flickr-style-tag-splitting-in-ruby&lt;br /&gt;            m = m.split(/"(.+?)"|\s+/).reject {|sm| sm.empty? }&lt;br /&gt;            #m = m.split(/"(.+?)"|'(.+?)'|\s+/).reject {|sm| sm.empty? }&lt;br /&gt;            #m = m.split(/"(.+?)"|'(.+?)'|([[:punct:]])|\s+/).reject {|sm| sm.empty? }&lt;br /&gt;            ret.concat(m)&lt;br /&gt;            next&lt;br /&gt;&lt;br /&gt;         # example: xxx "abc""def" yyy&lt;br /&gt;         elsif open_quotes.zero? &amp;&amp; close_quotes.zero? &amp;&amp; m =~ /\A\s*["'][^"']+["']{2,}[^"']+["']\z/ &amp;&amp; m.count('"') % 2 == 0 &amp;&amp; m.count("'") % 2 == 0           &lt;br /&gt;            &lt;br /&gt;            m = m.gsub(/\x20\x20/, "\x20")&lt;br /&gt;            m = m.split(/"(.+?)"|\s+/).reject {|sm| sm.empty? }&lt;br /&gt;            #m = m.split(/"(.+?)"|'(.+?)'|\s+/).reject {|sm| sm.empty? }&lt;br /&gt;            ret.concat(m)&lt;br /&gt;            next&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;         elsif open_quotes.zero? &amp;&amp; close_quotes.zero? &amp;&amp; m =~ /\A\s"[^"]+"\z/ &amp;&amp; m.count('"') % 2 == 0 &amp;&amp; m.count("'") % 2 == 0&lt;br /&gt;            ret.concat(m.split(/"(.+?)"|\s+/).reject {|sm| sm.empty? })&lt;br /&gt;            next&lt;br /&gt;&lt;br /&gt;         elsif open_quotes.zero? &amp;&amp; close_quotes.zero? &amp;&amp; m =~ /\A\s'[^']+'\z/ &amp;&amp; m.count('"') % 2 == 0 &amp;&amp; m.count("'") % 2 == 0&lt;br /&gt;            ret.concat(m.split(/'(.+?)'|\s+/).reject {|sm| sm.empty? })&lt;br /&gt;            next&lt;br /&gt;&lt;br /&gt;         elsif open_quotes.zero? &amp;&amp; close_quotes.zero? &amp;&amp; m =~ /\A\s*["']\S+["']\z/ &amp;&amp; m.count('"') % 2 == 0 &amp;&amp; m.count("'") % 2 == 0&lt;br /&gt;            ret.concat(m.split(/"(.+?)"|\s+/).reject {|sm| sm.empty? })&lt;br /&gt;            next&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;         elsif m =~ /\A\s"\s[^"]+\s"\s\z/&lt;br /&gt;&lt;br /&gt;            next unless open_quotes == 0 &amp;&amp; close_quotes == 0&lt;br /&gt;            ret &lt;&lt; m.gsub(/\x20\x20/, "\x20").strip[1..-2]&lt;br /&gt;            next&lt;br /&gt;&lt;br /&gt;         elsif m =~ /\A\s'\s[^']+\s"\s\z/&lt;br /&gt;&lt;br /&gt;            next unless open_quotes == 0 &amp;&amp; close_quotes == 0&lt;br /&gt;            ret &lt;&lt; m.gsub(/\x20\x20/, "\x20").strip[1..-2]&lt;br /&gt;            next&lt;br /&gt;&lt;br /&gt;         elsif m =~ /\A\s'\s+'\s\z/&lt;br /&gt;&lt;br /&gt;            next unless open_quotes == 0 &amp;&amp; close_quotes == 0&lt;br /&gt;            ret &lt;&lt; m.gsub(/\x20\x20/, "\x20").strip[1..-2]&lt;br /&gt;            next&lt;br /&gt;&lt;br /&gt;         elsif m =~ /\A\s"\s+"\s\z/&lt;br /&gt;&lt;br /&gt;           next unless open_quotes == 0 &amp;&amp; close_quotes == 0&lt;br /&gt;           ret &lt;&lt; m.gsub(/\x20\x20/, "\x20").strip[1..-2]&lt;br /&gt;           next&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;         elsif m =~ /\A\s""+\z/&lt;br /&gt;&lt;br /&gt;            l = m.strip.length&lt;br /&gt;            ar &lt;&lt; [:dqoblock, index, l]&lt;br /&gt;            old_open_quotes = open_quotes&lt;br /&gt;            open_quotes += l&lt;br /&gt;&lt;br /&gt;            if close_quotes == 0 &amp;&amp; old_open_quotes == 0 &amp;&amp; open_quotes % 2 == 0 &amp;&amp; post_match !~ /"/&lt;br /&gt;               ret &lt;&lt; m[2..-2] &lt;br /&gt;               open_quotes = 0&lt;br /&gt;               ar.pop&lt;br /&gt;               next&lt;br /&gt;            end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;         elsif m =~ /\A\s''+\z/&lt;br /&gt;&lt;br /&gt;            l = m.strip.length&lt;br /&gt;            ar &lt;&lt; [:sqoblock, index, l]&lt;br /&gt;            old_open_quotes = open_quotes&lt;br /&gt;            open_quotes += l&lt;br /&gt;&lt;br /&gt;            if close_quotes == 0 &amp;&amp; old_open_quotes == 0 &amp;&amp; open_quotes % 2 == 0 &amp;&amp; post_match !~ /'/&lt;br /&gt;               ret &lt;&lt; m[2..-2] &lt;br /&gt;               open_quotes = 0&lt;br /&gt;               ar.pop&lt;br /&gt;               next&lt;br /&gt;            end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;         elsif m =~ /\A[^"]""+\z/&lt;br /&gt;&lt;br /&gt;            l = m[1..-1].strip.length&lt;br /&gt;            ar &lt;&lt; [:dqcblock, index+l-1, l]      #  index+l-1 is the index of the last closing quote: ''"'[']&lt;br /&gt;            old_close_quotes = close_quotes&lt;br /&gt;            close_quotes += l&lt;br /&gt;&lt;br /&gt;            if open_quotes == 0 &amp;&amp; old_close_quotes == 0 &amp;&amp; close_quotes % 2 == 0 &amp;&amp; post_match !~ /"/&lt;br /&gt;               ret &lt;&lt; m[2..-2] &lt;br /&gt;               close_quotes = 0&lt;br /&gt;               ar.pop&lt;br /&gt;               next&lt;br /&gt;            end&lt;br /&gt;&lt;br /&gt;         elsif m =~ /\A[^']''+\z/&lt;br /&gt;&lt;br /&gt;            l = m[1..-1].strip.length&lt;br /&gt;            ar &lt;&lt; [:sqcblock, index+l-1, l]&lt;br /&gt;            old_close_quotes = close_quotes&lt;br /&gt;            close_quotes += l&lt;br /&gt;&lt;br /&gt;            if open_quotes == 0 &amp;&amp; old_close_quotes == 0 &amp;&amp; close_quotes % 2 == 0 &amp;&amp; post_match !~ /'/&lt;br /&gt;               ret &lt;&lt; m[2..-2] &lt;br /&gt;               close_quotes = 0&lt;br /&gt;               ar.pop&lt;br /&gt;               next&lt;br /&gt;            end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;         elsif m =~ /\A\s'\z/&lt;br /&gt;&lt;br /&gt;            ar &lt;&lt; [:sqo, index, 1]&lt;br /&gt;            open_quotes += 1&lt;br /&gt;&lt;br /&gt;         elsif m =~ /\A\S'\z/&lt;br /&gt;&lt;br /&gt;            ar &lt;&lt; [:sqc, index, 1]&lt;br /&gt;            close_quotes += 1&lt;br /&gt;&lt;br /&gt;         elsif m =~ /\A\s"\z/&lt;br /&gt;&lt;br /&gt;            ar &lt;&lt; [:dqo, index, 1]&lt;br /&gt;            open_quotes += 1&lt;br /&gt;&lt;br /&gt;         elsif m =~ /\A\S"\z/&lt;br /&gt;&lt;br /&gt;            ar &lt;&lt; [:dqc, index, 1]&lt;br /&gt;            close_quotes += 1&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;         else&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;            if m =~ /\A\s"\s\z/              # " surrounded by whitespace&lt;br /&gt;&lt;br /&gt;               if open_quotes &gt; close_quotes&lt;br /&gt;&lt;br /&gt;                  ar &lt;&lt; [:dqc, index, 1]&lt;br /&gt;                  close_quotes += 1&lt;br /&gt;&lt;br /&gt;                  # avoid :sqo followed by :dqc or :sqc followed by :dqc&lt;br /&gt;                  if post_match =~ /"/ &amp;&amp; open_quotes == close_quotes &amp;&amp; (ar.at(-2).first == :sqo || ar.at(-2).first == :sqc)&lt;br /&gt;                     ar.pop&lt;br /&gt;                     ar &lt;&lt; [:dqo, index, 1]&lt;br /&gt;                     close_quotes -= 1&lt;br /&gt;                     open_quotes += 1&lt;br /&gt;                  end&lt;br /&gt;&lt;br /&gt;               else &lt;br /&gt;&lt;br /&gt;                  ar &lt;&lt; [:dqo, index, 1]&lt;br /&gt;                  open_quotes += 1&lt;br /&gt;&lt;br /&gt;               end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;            elsif m =~ /\A\s'\s\z/          # ' surrounded by whitespace&lt;br /&gt;&lt;br /&gt;               if open_quotes &gt; close_quotes&lt;br /&gt;&lt;br /&gt;                  ar &lt;&lt; [:sqc, index, 1]&lt;br /&gt;                  close_quotes += 1&lt;br /&gt;&lt;br /&gt;                  # avoid :dqo followed by :sqc or :dqc followed by :sqc&lt;br /&gt;                  if post_match =~ /'/ &amp;&amp; open_quotes == close_quotes &amp;&amp; (ar.at(-2).first == :dqo || ar.at(-2).first == :dqc)&lt;br /&gt;                     ar.pop&lt;br /&gt;                     ar &lt;&lt; [:sqo, index, 1]&lt;br /&gt;                     close_quotes -= 1&lt;br /&gt;                     open_quotes += 1&lt;br /&gt;                  end&lt;br /&gt;&lt;br /&gt;               else &lt;br /&gt;&lt;br /&gt;                  ar &lt;&lt; [:sqo, index, 1]&lt;br /&gt;                  open_quotes += 1&lt;br /&gt;&lt;br /&gt;               end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;            elsif m =~ /\A\s["']["']+\z/              # :qoblock: xxx "'""'abc yyy&lt;br /&gt;&lt;br /&gt;               l = m[1..-1].strip.length&lt;br /&gt;               ar &lt;&lt; [:qoblock, index, l]&lt;br /&gt;               old_open_quotes = open_quotes&lt;br /&gt;               open_quotes += l&lt;br /&gt;&lt;br /&gt;               if close_quotes == 0 &amp;&amp; old_open_quotes == 0 &amp;&amp; open_quotes % 2 == 0 &amp;&amp; post_match !~ /["']/&lt;br /&gt;                  ret &lt;&lt; m[2..-2] &lt;br /&gt;                  open_quotes = 0&lt;br /&gt;                  ar.pop&lt;br /&gt;                  next&lt;br /&gt;               end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;            elsif m =~ /\A[^"'\s]["']["']+\z/          # :qcblock: xxx abc"'""' yyy&lt;br /&gt;&lt;br /&gt;               l = m[1..-1].strip.length&lt;br /&gt;               ar &lt;&lt; [:qcblock, index+l-1, l]&lt;br /&gt;               old_close_quotes = close_quotes&lt;br /&gt;               close_quotes += l&lt;br /&gt;&lt;br /&gt;               if open_quotes == 0 &amp;&amp; old_close_quotes == 0 &amp;&amp; close_quotes % 2 == 0 &amp;&amp; post_match !~ /["']/&lt;br /&gt;                  ret &lt;&lt; m[2..-2] &lt;br /&gt;                  close_quotes = 0&lt;br /&gt;                  ar.pop&lt;br /&gt;                  next&lt;br /&gt;               end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;            elsif m =~ /\A\s*["'].*?["']\s*\z/       # last try  (experimental)&lt;br /&gt;&lt;br /&gt;               ret.concat(m.split(/"(.+?)"|\s+/).reject {|sm| sm.empty? })&lt;br /&gt;               next&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;            elsif m =~ /\A[^"']+[^"'\s]\z/          # part of quoted substring contains neither " nor '&lt;br /&gt;               next unless open_quotes == 0 &amp;&amp; close_quotes == 0&lt;br /&gt;               next if m.strip.empty?&lt;br /&gt;               ret &lt;&lt; m.gsub(/\x20\x20/, "\x20").strip; next&lt;br /&gt;            end&lt;br /&gt;&lt;br /&gt;         end&lt;br /&gt;&lt;br /&gt;         puts&lt;br /&gt;         puts "open_quotes:  #{open_quotes}\nclose_quotes: #{close_quotes}\n"&lt;br /&gt;         #puts "ar: #{ar.inspect}"&lt;br /&gt;&lt;br /&gt;         if open_quotes == close_quotes&lt;br /&gt;&lt;br /&gt;            #puts "open_quotes &amp; close_quotes: #{close_quotes}"&lt;br /&gt;            puts "ar: #{ar.inspect}"&lt;br /&gt;&lt;br /&gt;            ret &lt;&lt; s[ar.first[1]..ar.last[1]].gsub(/\x20\x20/, "\x20")[1..-2] unless ar.empty?&lt;br /&gt;&lt;br /&gt;            ar.clear&lt;br /&gt;            open_quotes = 0&lt;br /&gt;            close_quotes = 0&lt;br /&gt;&lt;br /&gt;         end&lt;br /&gt;&lt;br /&gt;      end   # scan 2&lt;br /&gt;&lt;br /&gt;      unless open_quotes.zero? &amp;&amp; close_quotes.zero?&lt;br /&gt;        error_code = 1&lt;br /&gt;        puts "\e[1mparsing error\e[m for the quoted string: #{str.strip.squeeze[0..20]}"&lt;br /&gt;        #raise "\e[1mparsing error\e[m for the quoted string: #{str.strip.squeeze[0..20]}"&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;   end   # if&lt;br /&gt;&lt;br /&gt;end   # scan 1&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;num_of_chars2 = ret.join.count('a-zA-Z_0-9', "^\000ds")&lt;br /&gt;&lt;br /&gt;unless num_of_chars1 == num_of_chars2&lt;br /&gt;   error_code = 1&lt;br /&gt;   puts "\n\e[1mparsing error due to wrong number of characters a-zA-Z_0-9\e[m: \n#{num_of_chars2} instead of #{num_of_chars1}\n"&lt;br /&gt;   #raise "\e[1mparsing error due to wrong number of characters a-zA-Z_0-9\e[m: \n#{num_of_chars2} instead of #{num_of_chars1}\n in #{str.strip.squeeze[0..20]}"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# use Shellwords in case the quote matching above failed&lt;br /&gt;if error_code == 1       &lt;br /&gt;#if error_code == 1 || ret.join =~ /\A["']+\z/        &lt;br /&gt;   require 'shellwords'&lt;br /&gt;   ret.clear&lt;br /&gt;   ret.concat(Shellwords::shellwords(str))&lt;br /&gt;   #str =~ /\A\S+\z/ ? ret.concat(str.split(/"(.+?)"|\s+/).reject {|sm| sm.empty? }) : ret.concat(Shellwords::shellwords(str))&lt;br /&gt;end &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;puts "\n\e[1mResult\e[m:\n\n"&lt;br /&gt;ret.each_with_index do |t,i| &lt;br /&gt;   # decode encoded escaped quotes &lt;br /&gt;   t = t.gsub(/\000d\000|\000s\000/) { |m| m =~ /^\000d\000$/ ? '\"' : "\\'" }&lt;br /&gt;   puts "#{i+1}:  #{t.inspect}" &lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;puts "\n\e[1mShellwords\e[m:\n\n"&lt;br /&gt;require 'shellwords'&lt;br /&gt;Shellwords::shellwords(str2).each_with_index { |t,i| puts "#{i+1}:  #{t.inspect}" }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#----------------------&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# matching quoted strings using backreferences&lt;br /&gt;# See: Regexes in Depth: Advanced Quoted String Matching,&lt;br /&gt;# http://blog.stevenlevithan.com/archives/match-quoted-string&lt;br /&gt;&lt;br /&gt;str = '"abc"'&lt;br /&gt;&lt;br /&gt;regex = %r{(["'])([^"']*)(\1)}&lt;br /&gt;regex = %r{(["'])([^\1]*)(\1)}&lt;br /&gt;p regex&lt;br /&gt;&lt;br /&gt;str.scan(regex) { |m| p m; p $1 &lt;&lt; $2 &lt;&lt; $3 }&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Sun, 04 May 2008 18:47:17 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/5459</guid>
      <author>ntk ()</author>
    </item>
  </channel>
</rss>
