Лучший способ закодировать это, преобразование строки в карту в Groovy - PullRequest
14 голосов
/ 11 мая 2010

У меня есть строка типа

def data = "session=234567893egshdjchasd&userId=12345673456&timeOut=1800000"

Я хочу преобразовать это в карту

 ["session", 234567893egshdjchasd]
 ["userId", 12345673456]
 ["timeout", 1800000]

Это мой нынешний способ,

 def map = [:]

 data.splitEachLine("&"){

   it.each{ x ->

     def object = x.split("=")
     map.put(object[0], object[1])

   }

 }

Это работает, но есть ли более эффективный способ?

Ответы [ 8 ]

24 голосов
/ 11 мая 2010

Я не знаю, думаю, что это будет работать быстрее, но это дает о себе знать с точки зрения синтаксической экономии:

def data = 'session=234567893egshdjchasd&userId=12345673456&timeOut=1800000'
def result = data.split('&').inject([:]) { map, token -> 
    //Split at "=" and return map with trimmed values
    token.split('=').with { 
        map[it[0].trim()] = it[1].trim() 
    }
    map 
}

Лично мне нравится ответ Дона за удобочитаемость и удобство обслуживания, но в зависимости от контекста это может быть уместно.

Редактировать: На самом деле это переформатированный однострочный.

13 голосов
/ 11 мая 2010

Я не знаю, является ли это более эффективным, но на мой взгляд, это немного проще (YMMV) * ​​1001 *

def data = "session=234567893egshdjchasd&userId=12345673456&timeOut=1800000"
def map = [:]

data.split("&").each {param ->
    def nameAndValue = param.split("=")
    map[nameAndValue[0]] = nameAndValue[1]
}
6 голосов
/ 12 мая 2010

Если вы ищете эффективные, регулярные выражения находятся там, где:

def data = "session=234567893egshdjchasd&userId=12345673456&timeOut=1800000"
def map = [:]
data.findAll(/([^&=]+)=([^&]+)/) { full, name, value ->  map[name] = value }

println map

печатает:

[session:234567893egshdjchasd, userId:12345673456, timeOut:1800000]

Если вы не знакомы с регулярными выражениями, это можетвыглядеть немного посторонним, но это действительно не так сложно.У него просто две (группы), первая группа - любой символ, кроме «&» или «=».Вторая группа - это любой символ, кроме "=".Группы захвата находятся по обе стороны от "=".

2 голосов
/ 13 мая 2016

После некоторого поиска "collectEntries ()" - волшебная вещь, которую нужно использовать, она создает элемент карты. Работайте так же, как «collect ()», который создает список. Так дано

def params = "a1=b1&a2=b2&a3&a4=&a5=x=y"

однострочник

map = params.tokenize("&").collectEntries{ 
          it.split("=",2).with{ 
              [ (it[0]): (it.size()<2) ? null : it[1] ?: null ] 
          }
      }

, который создает

map = [a1:b1, a2:b2, a3:null, a4:null, a5:x=y]

В зависимости от того, как вы хотите обрабатывать случаи «a3» и «a4 =», вы также можете использовать несколько более короткую версию

...
[ (it[0]): (it.size()<2) ? null : it[1] ] 
...

и тогда вы получите это:

map = [a1:b1, a2:b2, a3:null, a4:, a5:x=y]
1 голос
/ 25 февраля 2016

Вот мое усилие, которое инициализирует и заполняет карту за один раз, и избегает метода инъекции, который лично мне трудно использовать:

    def map = data.split('&').collectEntries {
        def kvp = it.split('=').collect { string ->
            string = string.trim()
            return string
    }
    [(kvp[0]): kvp.size() > 1 ? kvp[1] ?: '' : '']
    // the null check is almost certainly overkill so you could use :-
    // [(kvp[0]): kvp.size() > 1 ? kvp[1] : '']
    // this just checks that a value was found and inserts an empty string instead of null 
}
1 голос
/ 04 декабря 2015

Если вы используете Grails, лучший способ, который я нахожу, это WebUtils функция из QueryString.

https://grails.github.io/grails-doc/2.0.x/api/org/codehaus/groovy/grails/web/util/WebUtils.html

1 голос
/ 18 января 2011

Если вы находитесь в контроллере Grails, то это просто и понятно:

GrailsParameterMap map = new GrailsParameterMap(request)

http://grails.org/doc/latest/api/org/codehaus/groovy/grails/web/servlet/mvc/GrailsParameterMap.html

0 голосов
/ 31 октября 2018

Я бы не советовал использовать сплит вообще.

Split создает новую строку, тогда как при создании коллекции переменных среды вам, вероятно, понадобится список карт.

Токенизация как на начальный разрыв (&), так и на вложенный разрыв (=). Хотя большинство интерпретаторов по-прежнему работают, некоторые могут выполнить разделение буквально, и в результате вы получите список строк, а не список карт.

def data= "test1=val1&test2=val2"
def map = [:]

map = data.tokenize("&").collectEntries {
    it.tokenize("=").with {
        [(it[0]):it[1]]
    }
}
...