найти JSON в строке с пределом рекурсии в r (windows) - PullRequest
0 голосов
/ 11 января 2020

Я хочу создать функцию, которая извлекает jsons из строк обобщенным образом c (для форматов переменных строк) с R на Windows.

Благодаря # SO я использую:

allJSONS <- gregexpr(
  pattern = "\\{(?:[^{}]|(?R))*?\\}",
  perl = TRUE,
  text = jsonString
) %>%
  regmatches(x = jsonString)

Это хорошо работает для некоторых строк. Для других функция завершается с предупреждением.

Ошибка:

Для некоторых строк я получаю предупреждение / ошибку:

Предупреждение : В gregexpr (pattern = "\ {(?: [^ {}] | (? R)) *? \}", perl = TRUE, text = jsonString): предел рекурсии, достигнутый в PCRE для элемента 1, может быть увеличен C размер стека для процесса R

Здесь ответили на вопрос Linux: Ошибка: C использование стека слишком близко к пределу . В комментариях было рекомендовано задать новый вопрос с тегом Windows.

Воспроизводимый пример:

Я загрузил пример данных на Github: https://github.com/TyGu1/findJSON/raw/master/jsonString.RData. (Прямая загрузка через load(url(…))) мне как-то не удалась, но загрузка вручную и использование load() работают для меня.

(Обратите внимание, что это только примерные данные. Я ищу универсальное c решение.)

load(DOWNLOADED FILE)
allJSONS <- gregexpr(
  pattern = "\\{(?:[^{}]|(?R))*?\\}",
  perl = TRUE,
  text = jsonString
) %>%
  regmatches(x = jsonString)

Доказательство того, что на самом деле существует JSON:

library(magrittr)  
library(jsonlite)

rp <- gsub(pattern = "memmCellmemm(", fixed = TRUE, replacement = "", x = jsonString)
rp <- substring(rp, first = 1, last = nchar(rp)-1) 
json <- rp %>% fromJSON

Цель:

Создать функцию, которая извлекает jsons из строк обобщенным образом c (для форматов переменных строк) с R на Windows.

Я знаю, что могу извлечь json с предоставленным кодом:

rp <- gsub(pattern = "memmCellmemm(", fixed = TRUE, replacement = "", x = jsonString)
rp <- substring(rp, first = 1, last = nchar(rp)-1) 

но мне нужна более универсальная c функция, такая как регулярное выражение в верхней части, потому что форматы файлов могут сильно различаться по входным данным.

Ответы [ 2 ]

2 голосов
/ 16 января 2020

Эта проблема возникает из этой части вашего регулярного выражения: (?:[^{}]|(?R))*. Просто изменив это на (?:[^{}]+|(?R))*, проблема исчезнет. Я не уверен, почему это происходит, но я предполагаю, что вы в основном упрощаете путь, который regex должен использовать для проверки строки, выполняя это (проверяя, не являются ли символы теми VS, и если он должен повторить шаблон).

gregexpr(
  pattern = "\\{(?:[^{}]+|(?R))*?\\}",
  perl = TRUE,
  text = jsonString
)

#> [[1]]
#> [1] 14
#> attr(,"match.length")
#> [1] 134539
#> attr(,"index.type")
#> [1] "chars"
#> attr(,"useBytes")
#> [1] TRUE

Если вы хотите, однако, более полное решение, основанное на этом ответе , вы можете использовать что-то вроде этого:

my_json_string = "adjkd({\"asdasd\": {\"asdasd\": 1234}}{\"asdasd\": 1234})"    
json_regexp = paste0(
    "(?(DEFINE)",
        "(?<number>-?(?=[1-9]|0(?!\\d))\\d+(\\.\\d+)?([eE][+-]?\\d+)?)",
        "(?<boolean>true|false|null)",
        "(?<string>\"([^\"\\\\]*|\\\\[\"\\\\bfnrt\\/]|\\\\u[0-9a-fA-F]{4})*\")",
        "(?<array>\\[(?:(?&json)(?:,(?&json))*)?\\s*\\])",
        "(?<pair>\\s*(?&string)\\s*:(?&json))",
        "(?<object>\\{(?:(?&pair)(?:,(?&pair))*)?\\s*\\})",
        "(?<json>\\s*(?:(?&object)|(?&array)|(?&number)|(?&boolean)|(?&string))\\s*)",
    ")",
    "(?&json)"
)

gregexpr(json_regexp, my_json_string, perl=T) 
    %>% regmatches(x = my_json_string)

#> [[1]]
#> [1] "{\"asdasd\": {\"asdasd\": 1234}}" "{\"asdasd\": 1234}"  

Это также работает с вашим json строка.

gregexpr(json_regexp, jsonString, perl=T)
#> [[1]]
#> [1] 14
#> attr(,"match.length")
#> [1] 134539
#> attr(,"index.type")
#> [1] "chars"
#> attr(,"useBytes")
#> [1] TRUE
#> attr(,"capture.start")
#>      number     boolean string   array pair object json
#> [1,]      0 0 0       0      0 0     0    0      0    0
#> attr(,"capture.length")
#>      number     boolean string   array pair object json
#> [1,]      0 0 0       0      0 0     0    0      0    0
#> attr(,"capture.names")
#>  [1] "number"  ""        ""        "boolean" "string"  ""        "array"   "pair"    "object"  "json"   
2 голосов
/ 16 января 2020
/(([\x20\t\h\r\n]*)(?:(?:{(?:(?2)|,?((?2)"(?:[^\\"\x0\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA\xB\xC\xD\xE\xF\x7F]|\\u[0-9A-F]{4}|\\t|\\r|\\n|\\f|\\b|\\\/|\\\\|\\"|\\")*"(?2)):(?1))+})|(?:\[(?:(?2)|,?(?1))+\])|(?3)|(?:-?(?:[1-9](?:[0-9]+)?|0)(?:\.[0-9]+)?(?:[Ee][+-]?[0-9]+)?)|true|false|null)(?2))/im

Я написал это RegEx для сопоставления JSON в строке с php с использованием PCRE И это работает. Он основан на этой странице . Вы, вероятно, хотите код на другом языке, но я не имею никакого представления об этом языке. Но потому что это регулярное выражение, я думаю, что оно может быть преобразовано, как и, вероятно, не будет иметь большой разницы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...