2010-10-27 5 views
2

У меня есть специальные строки, такие как name1="value1" name2='value2'. Значения могут содержать пробелы и ограничены одинарными кавычками или двойными кавычками. Имена никогда не содержат пробелов. пары имя/значение разделяются пробелами.Как разбить строку в Ruby?

Я хочу, чтобы разобрать их в список пар имя-значение, как этот

string.magic_split() => { "name1"=>"value1", "name2"=>"value2" } 

Если Рубин понял lookaround утверждения, я мог бы сделать это с помощью

string.split(/[\'\"](?=\s)/).each do |element| 
    element =~ /(\w+)=[\'\"](.*)[\'\"]/ 
    hash[$1] = $2 
end 

но Руби не понимает lookaround утверждений, поэтому я несколько застрял.

Тем не менее, я уверен, что есть намного более элегантные способы решения этой проблемы в любом случае, поэтому я обращаюсь к вам. У вас есть хорошая идея для решения этой проблемы?

+0

Единственный правильный способ разобрать все - это один символ за раз. – Sorpigal

+0

Является ли строка ввода стандартным форматом? –

+0

Может ли значения содержать кавычки? –

ответ

6

Это терпит неудачу в таких ценностях, как «привет», - сказала она, - но это может быть достаточно хорошо.

str = %q(name1="value1" name2='value 2') 
p Hash[ *str.chop.split(/' |" |='|="/) ] 
#=> {"name1"=>"value1", "name2"=>"value 2"} 
+0

хорошо, вы можете избежать измельчения, если вместо этого вы разделите (/ '| "| =' | = "| '$ |" $ /) – jordinl

+0

Ничего себе, это классное решение. Спасибо! Не могли бы вы объяснить, что делает '*' перед 'str'? – bastibe

+0

Результат из' str.chop.split' - это массив. '*' преобразует элементы этого массива в несколько параметров, которые должны быть переданы в метод '[]' 'Hash'. – mikej

2

Это не полный ответ, но Oniguruma, стандартная библиотека регулярных выражений 1.9 поддерживает опорные утверждения. Он может быть установлен как драгоценный камень, если вы используете Ruby 1.8.x.

Это сказало, а как Sorpigal прокомментировал, вместо того, чтобы использовать регулярное выражение, я был бы склонен к итерации по строке один символ за раз, отслеживая, находитесь ли вы в части имени, когда вы достигаете знака равенства, когда вы находитесь в кавычках и когда вы достигаете согласованной цитаты закрытия. По достижении заключительной цитаты вы можете поместить имя и значение в хэш и перейти к следующей записи.

+0

Рубин на OSX застрял на 1.8.7 на данный момент. (Я знаю, что могу обновить его вручную, но я не хочу сталкиваться с проблемами совместимости с инструментами XCode и т. Д.) – bastibe

0

У попробовать с: /[='"] ?/

Я не знаю синтаксис Ruby, но здесь является сценарий Perl можно перевести

#!/usr/bin/perl 
use 5.10.1; 
use warnings; 
use strict; 
use Data::Dumper; 

my $str = qq/name1="val ue1" name2='va lue2'/; 

my @list = split/[='"] ?/,$str; 
my %hash; 
for (my $i=0; $i<@list;$i+=3) { 
    $hash{$list[$i]} = $list[$i+2]; 
} 
say Dumper \%hash; 

Выход:

$VAR1 = { 
      'name2' => 'va lue2', 
      'name1' => 'val ue1' 
     }; 
1
class String 

    def magic_split 
    str = self.gsub('"', '\'').gsub('\' ', '\'\, ').split('\, ').map{ |str| str.gsub("'", "").split("=") } 
    Hash[str] 
    end 

end 
1

Это должно сделать это за вас.

class SpecialString 
    def self.parse(string) 
    string.split.map{|s| s.split("=") }.inject({}) {|h, a| h[a[0]] = a[1].gsub(/"|'/, ""); h } 
    end 
end 
Смежные вопросы