Что нового

С помощью регулярных выражений выбрать нужные значения из строки с данными

Grizli

Новичок
Сообщения
48
Репутация
2
Здравствуйте.
Помогите составить рег. выражение. Имеется строка
Код:
Result: {"orders":[{"orderId":"378886494","orderStatus":"new","lastTimestamp":1436248285469,"orderPrice":7.6e-7,"orderQuantity":65,"avgPrice":0,"quantityLeaves":65,"type":"limit","timeInForce":"GTC","cumQuantity":0,"clientOrderId":"d184e53dbe36bc0f1cd7ac219cbb15a1","symbol":"DOGEBTC","side":"sell","execQuantity":0}]}
Нужно получить массив со всеми значениями. Получаю вот так:
Код:
$bids=StringRegExp($zapros, '"(.*?)"',3)
If @error Then
		ConsoleWrite(@error&" &&")
	Exit
	EndIf
_ArrayDisplay($bids, "флаг=3")

Получаю вот такой массив:
L8wqLnxV.png

То есть в массив не попадают все цифровые значения, не обрамленные кавычками.
 

СН3СН2ОН

Знающий
Сообщения
78
Репутация
12
Код:
#include <array.au3>
$zapros='Result: {"orders":[{"orderId":"378886494","orderStatus":"new","lastTimestamp":1436248285469,"orderPrice":7.6e-7,"orderQuantity":65,"avgPrice":0,"quantityLeaves":65,"type":"limit","timeInForce":"GTC","cumQuantity":0,"clientOrderId":"d184e53dbe36bc0f1cd7ac219cbb15a1","symbol":"DOGEBTC","side":"sell","execQuantity":0}]}'
$zapros=StringRegExpReplace($zapros, '(?si).*\[(.*?)\].*','$1')
ConsoleWrite($zapros)
$bids=StringRegExp($zapros, '(?si)\{{0,1}(.*?)[\:\,\}]',3)
_ArrayDisplay($bids)
 

alex33

Скриптер
Сообщения
1,457
Репутация
186
А мне кажется, что лучше обойтись без регулярных выражений, ведь это же JSON.
Примерно так:
Код:
Local $oSC = ObjCreate("ScriptControl")
If Not IsObj($oSC) Then Exit 1
$oSC.Language = "JavaScript"

Local $json = '{"orders":[{"orderId":"378886494","orderStatus":"new","lastTimestamp":1436248285469,"orderPrice":7.6e-7,"orderQuantity":65,"avgPrice":0,"quantityLeaves":65,"type":"limit","timeInForce":"GTC","cumQuantity":0,"clientOrderId":"d184e53dbe36bc0f1cd7ac219cbb15a1","symbol":"DOGEBTC","side":"sell","execQuantity":0}]}'

Local $orders = $oSC.Eval("eval('(" & $json & ")').orders;")
If Not IsObj($orders) Then Exit 2
For $order In $orders
	ConsoleWrite(StringFormat("orderId: %s; orderStatus: %s; ...\r\n", $order.orderId, $order.orderStatus))
Next
 
Автор
G

Grizli

Новичок
Сообщения
48
Репутация
2
Спасибо СН3СН2ОН за вариант.
Вот еще вариант от меня, пока разбирался с проблемой вот так получилось:
Код:
#include <Array.au3>

Local $aReturn, $aInhaber, $aHobbies, $aStandort, $sText
$sText ='{"orderId":"378886494","orderStatus":"new","lastTimestamp":1436248285469,"orderPrice":7.6e-7,"orderQuantity":65,"avgPrice":0,"quantityLeaves":65,"type":"limit","timeInForce":"GTC","cumQuantity":0,"clientOrderId":"d184e53dbe36bc0f1cd7ac219cbb15a1","symbol":"DOGEBTC","side":"sell","execQuantity":0}]}'

$aReturn = _JSON_Decode($sText)


Func _JSON_Decode($sString)
    Local $iIndex, $aVal, $sOldStr = $sString, $b

    $sString = StringStripCR(StringStripWS($sString, 7))
    If Not StringRegExp($sString, "(?i)^\{.+}$") Then Return SetError(1, 0, 0)
    Local $aArray[1][2], $iIndex = 0
    $sString = StringMid($sString, 2)

    Do
        $b = False

        $aVal = StringRegExp($sString, '^"([^"]+)"\s*:\s*(["{[]|[-+]?\d+(?:(?:\.\d+)?[eE][+-]\d+)?|true|false|null)', 2) ; Get value & next token
        If @error Then
            ConsoleWrite("!> StringRegExp Error getting next Value." & @CRLF)
            ConsoleWrite($sString & @CRLF)
            $sString = StringMid($sString, 2) ; maybe it works when the string is trimmed by 1 char from the left ?
            ContinueLoop
        EndIf

        $aArray[$iIndex][0] = $aVal[1] ; Key
        $sString = StringMid($sString, StringLen($aVal[0]))

        Switch $aVal[2] ; Value Type (Array, Object, String) ?
            Case '"' ; String
                ; Value -> Array subscript. Trim String after that.

                $aArray[$iIndex][1] = StringMid($sString, 2, StringInStr($sString, """", 1, 2) - 2)
                $sString = StringMid($sString, StringLen($aArray[$iIndex][1]) + 3)

                ReDim $aArray[$iIndex + 2][2]
                $iIndex += 1

            Case '{' ; Object
                ; Recursive function call which will decode the object and return it.
                ; Object -> Array subscript. Trim String after that.

                $aArray[$iIndex][1] = _JSON_Decode($sString)
                $sString = StringMid($sString, @extended + 2)
                If StringLeft($sString, 1) = "," Then $sString = StringMid($sString, 2)

                $b = True
                ReDim $aArray[$iIndex + 2][2]
                $iIndex += 1

            Case '[' ; Array
                ; Decode Array
                $sString = StringMid($sString, 2)
                Local $aRet[1], $iArIndex = 0 ; create new array which will contain the Json-Array.

                Do
                    $sString = StringStripWS($sString, 3) ; Trim Leading & trailing spaces
                    $aNextArrayVal = StringRegExp($sString, '^\s*(["{[]|\d+(?:(?:\.\d+)?[eE]\+\d+)?|true|false|null)', 2)
                    Switch $aNextArrayVal[1]
                        Case '"' ; String
                            ; Value -> Array subscript. Trim String after that.
                            $aRet[$iArIndex] = StringMid($sString, 2, StringInStr($sString, """", 1, 2) - 2)
                            $sString = StringMid($sString, StringLen($aRet[$iArIndex]) + 3)

                        Case "{" ; Object
                            ; Recursive function call which will decode the object and return it.
                            ; Object -> Array subscript. Trim String after that.
                            $aRet[$iArIndex] = _JSON_Decode($sString)
                            $sString = StringMid($sString, @extended + 2)

                        Case "["
                            MsgBox(0, "", "Array in Array. WTF is up with this JSON shit?")
                            MsgBox(0, "", "This should not happen! Please post this!")
                            Exit 0xDEADBEEF

                        Case Else
                            ConsoleWrite("Array Else (maybe buggy?)" & @CRLF)
                            $aRet[$iArIndex] = $aNextArrayVal[1]
                    EndSwitch

                    ReDim $aRet[$iArIndex + 2]
                    $iArIndex += 1

                    $sString = StringStripWS($sString, 3) ; Leading & trailing
                    If StringLeft($sString, 1) = "]" Then ExitLoop
                    $sString = StringMid($sString, 2)
                Until False

                $sString = StringMid($sString, 2)
                ReDim $aRet[$iArIndex]
                $aArray[$iIndex][1] = $aRet

                ReDim $aArray[$iIndex + 2][2]
                $iIndex += 1

            Case Else ; Number, bool
                ; Value (number (int/flaot), boolean, null) -> Array subscript. Trim String after that.
                $aArray[$iIndex][1] = $aVal[2]
                ReDim $aArray[$iIndex + 2][2]
                $iIndex += 1
                $sString = StringMid($sString, StringLen($aArray[$iIndex][1]) + 2)
        EndSwitch

        If StringLeft($sString, 1) = "}" Then
            StringMid($sString, 2)
            ExitLoop
        EndIf
        If Not $b Then $sString = StringMid($sString, 2)
    Until False

    ReDim $aArray[$iIndex][2]
    Return SetError(0, StringLen($sOldStr) - StringLen($sString), $aArray)
EndFunc   ;==>_JSON_Decode

На выходе получился массив как мне нужно, но по скорости выполнения вариант одинаков с вариантом СН3СН2ОН.
Подскажите alex33 как с максимальной производительностью(за минимальное время) получить массив значений вашим вариантом, что-то у меня получились слишком громоздкие варианты. Может ваш вариант без регулярных выражений будет быстрее.
 

alex33

Скриптер
Сообщения
1,457
Репутация
186
Grizli сказал(а):
Подскажите alex33 как с максимальной производительностью(за минимальное время) получить массив значений вашим вариантом, что-то у меня получились слишком громоздкие варианты. Может ваш вариант без регулярных выражений будет быстрее.
А зачем вам массив? Вот внутри цикла доступны все переменные и ими можно манипулировать как угодно. Цикл будет проходить по всем объектам order.


Добавлено:
Сообщение автоматически объединено:

Ну если так нужен массив, можно как-нибудь так: :smile:
Код:
#include <Array.au3> ; for _ArrayDisplay
Local $json = '{"orders":[{"orderId":"378886494","orderStatus":"new","lastTimestamp":1436248285469,"orderPrice":7.6e-7,"orderQuantity":65,"avgPrice":0,"quantityLeaves":65,"type":"limit","timeInForce":"GTC","cumQuantity":0,"clientOrderId":"d184e53dbe36bc0f1cd7ac219cbb15a1","symbol":"DOGEBTC","side":"sell","execQuantity":0}]}'
Local $aResult = _json_decode($json)
If @error Then Exit MsgBox(16, "json decode error", "Error " & @error)
_ArrayDisplay($aResult)

Func _json_decode($sJson)
	Local $array[0][0], $i = 0
	Local $oSC = ObjCreate("ScriptControl")
	If Not IsObj($oSC) Then Return SetError(1, 0, 0)
	$oSC.Language = "JavaScript"
	Local $orders = $oSC.Eval("eval('(" & $sJson & ")').orders;")
	If Not IsObj($orders) Then Return SetError(2, 0, 0)
	$i = 0
	For $order In $orders
		ReDim $array[$i + 1][14]
		$array[$i][0] = $order.orderId
		$array[$i][1] = $order.orderStatus
		$array[$i][2] = $order.lastTimestamp
		$array[$i][3] = $order.orderPrice
		$array[$i][4] = $order.orderQuantity
		$array[$i][5] = $order.avgPrice
		$array[$i][6] = $order.quantityLeaves
		$array[$i][7] = $order.type
		$array[$i][8] = $order.timeInForce
		$array[$i][9] = $order.cumQuantity
		$array[$i][10] = $order.clientOrderId
		$array[$i][11] = $order.symbol
		$array[$i][12] = $order.side
		$array[$i][13] = $order.execQuantity
		$i += 1
	Next
	Return $array
EndFunc   ;==>_json_decode

ArrayDisplay.jpg
 
Автор
G

Grizli

Новичок
Сообщения
48
Репутация
2
Странно, может быть я неправильно понимаю вот это время: >Exit code: 0 Time: 0.65
Это при выходе в SCiTE. Все 3 варианта имеют одинаковое время выполнения. Хотя по количеству строк кода и по принципу все 3 варианта разные.
Для меня очень желательно максимально быстрое выполнение данного функционала(в возможностях языка Autoit)
 

alex33

Скриптер
Сообщения
1,457
Репутация
186
Grizli сказал(а):
Странно, может быть я неправильно понимаю вот это время: >Exit code: 0 Time: 0.65
Это 0 секунд и 65 микросекунд. Я считаю, что это довольно быстро.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Grizli,
Мой вариант.
Код:
#include <Array.au3>

Local $sText, $aTmp, $aData[1], $iInd, $sHeader, $iTime = TimerInit()

$sText = '{"orders":[{"orderId":"378886494","orderStatus":"new","lastTimestamp":1436248285469,"orderPrice":7.6e-7,"orderQuantity":65,"avgPrice":0,"quantityLeaves":65,"type":"limit","timeInForce":"GTC","cumQuantity":0,"clientOrderId":"d184e53dbe36bc0f1cd7ac219cbb15a1","symbol":"DOGEBTC","side":"sell","execQuantity":0}]}'
$aTmp = StringSplit(StringRegExpReplace($sText, '[\{\}\]\[''"]', ''), ':,')
ReDim $aData[$aTmp[0] / 2][2]
$sHeader = $aTmp[1]
For $i = 2 To $aTmp[0] - 1 Step 2
	For $j = 0 To 1
		$aData[$iInd][$j] = $aTmp[$i + $j]
	Next
	$iInd += 1
Next
$aTmp = 0
ConsoleWrite(TimerDiff($iTime) & ' msec' & @LF)
_ArrayDisplay($aData, $sHeader)

Код:
#include <Array.au3>

Local $sText, $aTmp, $aData[1], $iInd, $sHeader, $iTime = TimerInit()

$sText = 'Result: {"orders":[{"orderId":"378886494","orderStatus":"new","lastTimestamp":1436248285469,"orderPrice":7.6e-7,"orderQuantity":65,"avgPrice":0,"quantityLeaves":65,"type":"limit","timeInForce":"GTC","cumQuantity":0,"clientOrderId":"d184e53dbe36bc0f1cd7ac219cbb15a1","symbol":"DOGEBTC","side":"sell","execQuantity":0}]}'

$aTmp = StringSplit(StringRegExpReplace($sText, '[\{\}\]\[''"]', ''), ':,')
ReDim $aData[$aTmp[0] / 2 - 1][2]
$sHeader = StringStripWS($aTmp[2], 7)
For $i = 3 To $aTmp[0] - 1 Step 2
	For $j = 0 To 1
		$aData[$iInd][$j] = $aTmp[$i + $j]
	Next
	$iInd += 1
Next
$aTmp = 0
ConsoleWrite(TimerDiff($iTime) & ' msec' & @LF)
_ArrayDisplay($aData, $sHeader)
 

СН3СН2ОН

Знающий
Сообщения
78
Репутация
12
нет предела совершенству
Заметьте, я ем "грязную" строку.
Код:
#include <array.au3>
$zapros='Result: {"orders":[{"orderId":"378886494","orderStatus":"new","lastTimestamp":1436248285469,"orderPrice":7.6e-7,"orderQuantity":65,"avgPrice":0,"quantityLeaves":65,"type":"limit","timeInForce":"GTC","cumQuantity":0,"clientOrderId":"d184e53dbe36bc0f1cd7ac219cbb15a1","symbol":"DOGEBTC","side":"sell","execQuantity":0}]}'

$bids=StringRegExp($zapros, '(?si)(?!.*\[)\{{0,1}(.*?)[\:\,\}](?<!\].)',3)
_ArrayDisplay($bids)


Давайте устроим тестирование
Код:
#include <array.au3>
$zapros='Result: {"orders":[{"orderId":"378886494","orderStatus":"new","lastTimestamp":1436248285469,"orderPrice":7.6e-7,"orderQuantity":65,"avgPrice":0,"quantityLeaves":65,"type":"limit","timeInForce":"GTC","cumQuantity":0,"clientOrderId":"d184e53dbe36bc0f1cd7ac219cbb15a1","symbol":"DOGEBTC","side":"sell","execQuantity":0}]}'
;$zapros=StringRegExpReplace($zapros, '(?si).*\[(.*?)\].*','$1')
;ConsoleWrite($zapros)
For $i = 1 to 100000
$bids=StringRegExp($zapros, '(?si)(?!.*\[)\{{0,1}(.*?)[\:\,\}](?<!\].)',3)
;_ArrayDisplay($bids)
Next
 

alex33

Скриптер
Сообщения
1,457
Репутация
186
СН3СН2ОН сказал(а):
Заметьте, я ем "грязную" строку.
OffTopic:

Да? Я не знал, что вы строками питаетесь :smile: Ну что? Вкусная строка то? :smile: :D
Ну так можно просто 'Result: ' заменить на '' и всё...
Код:
$zapros = StringReplace($zapros, 'Result: ', '')
 
Автор
G

Grizli

Новичок
Сообщения
48
Репутация
2
alex33 сказал(а):
Grizli сказал(а):
Странно, может быть я неправильно понимаю вот это время: >Exit code: 0 Time: 0.65
Это 0 секунд и 65 микросекунд. Я считаю, что это довольно быстро.
Я то думал что это 0.65 Sec, теперь все стало на свои места. Всем спасибо за участие и помощь.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Предупреждение За нарушение общих правил (пункт В.2):
Старайтесь избегать “Over quoting” (преувеличенное цитирование) - цитируйте только необходимую часть сообщения, которая наилучшим образом подчеркнёт суть цитируемого.


С уважением, ваш Модератор.
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
Grizli
Я то думал что это 0.65 Sec
Вы правильно думали - это действительно больше половины секунды, потому что SciTE выводит общее время работы скрипта в секундах. Если вам нужно измерить производительность части кода, то используйте
Код:
$t = TimerInit()
; код
ConsoleWrite(TimerDiff($t) & @CRLF)
Вот здесь уже время будет в миллисекундах, т.е. в данном случае 0.4567 будет половина миллисекунды, а 1.10 - чуть больше одной миллисекунды. Для большей точности измерений можно код поместить в цикл и разделить полученный результат на количество итераций.
 
Верх