提取字符串的属性

Extract attributes of an string

我必须在这里处理一个由肮脏的设计引起的问题。我得到一个字符串列表,想从中解析属性。不幸的是,我无法更改创建这些字符串的来源。

示例:

String s = "type=INFO, languageCode=EN-GB, url=http://www.whosebug.com, ref=1, info=Text, that may contain all kind of chars., deactivated=false"

现在我想提取属性 typelanguageCodeurlrefinfodeactivated

这里的问题是字段info,其文本不受引号限制。此字段中也可能出现逗号,因此我不能在字符串末尾使用逗号来找出结束位置。

此外,这些字符串并不总是包含所有属性。 typeinfodeactivated 总是存在的,其余的是可选的。

有什么解决这个问题的建议吗?

一种可能的解决方案是在输入中搜索 = 个字符,然后将其前面的单个单词作为字段名称 - 似乎您所有的字段名称都是单个单词(无空格)。如果是这种情况,则可以将 = 之后直到下一个字段名称(用于分隔 ,)的所有内容作为值。

这假定该值不能包含 =

编辑:

作为处理嵌入 = 的一种可能方法,您可以查看它前面的单词是否是您已知的字段名称 - 如果不是,您可以将 = 视为一个嵌入字符而不是运算符。然而,这假设您有一组固定的已知字段(其中一些可能不会总是出现)。如果您知道字段名称区分大小写,则可能会放宽此假设。

您可以使用正则表达式,捕获所有 "fixed" 组并使用 info 的剩余部分。如果 info 部分包含 ,= 字符,这甚至应该有效。这是一些简单的示例(使用 Python,但这应该不是问题...)。

>>> p = r"(type=[A-Z]+), (languageCode=[-A-Z]+), (url=[^,]+), (ref=\d), (info=.+?), (deactivated=(?:true|false))"
>>> s = "type=INFO, languageCode=EN-GB, url=http://www.whosebug.com, ref=1, info=Text, that may contain all kind of chars, even deactivated=true., deactivated=false"
>>> re.search(p, s).groups()
('type=INFO',
 'languageCode=EN-GB',
 'url=http://www.whosebug.com',
 'ref=1',
 'info=Text, that may contain all kind of chars, even deactivated=true.',
 'deactivated=false')

如果这些元素中的任何一个是可选的,您可以在这些组之后放置一个 ?,并将逗号设为可选。如果顺序可以不同,那就更复杂了。在这种情况下,不是使用一个 RegEx 一次捕获所有内容,而是使用多个 RegEx 捕获各个属性,然后在匹配下一个属性之前删除(替换为 '')字符串中的那些属性。最后,匹配 info.


进一步考虑,考虑到这些属性可以有任何顺序,更有希望捕获从一个关键字到下一个关键字的所有内容,而不考虑其实际内容,这与 Pshemo 的解决方案非常相似:

keys = "type|languageCode|url|ref|info|deactivated"
p = r"({0})=(.+?)(?=\, (?:{0})=|$)".format(keys)
matches = re.findall(p, s)

但这也可能在一些非常模糊的情况下失败,例如如果 info 属性包含类似 ', ref=foo' 的内容,包括逗号。然而,似乎没有办法解决这些歧义。如果你有一个像 info=in this string, ref=1, and in another, ref=2, ref=1 这样的字符串,它包含一个 ref 属性,还是三个,或者根本不包含 none?

假设元素的顺序是固定的,您可以像这样使用正则表达式编写解决方案

String s = "type=INFO, languageCode=EN-GB, url=http://www.whosebug.com, ref=1, info=Text, that may contain all kind of chars., deactivated=false";

String regex = //type, info and deactivated are always present
          "type=(?<type>.*?)"
        + "(?:, languageCode=(?<languageCode>.*?))?"//optional group
        + "(?:, url=(?<url>.*?))?"//optional group
        + "(?:, ref=(?<rel>.*?))?"//optional group
        + ", info=(?<info>.*?)"
        + ", deactivated=(?<deactivated>.*?)";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(s);
if(m.matches()){
    System.out.println("type -> "+m.group("type"));
    System.out.println("languageCode -> "+m.group("languageCode"));
    System.out.println("url -> "+m.group("url"));
    System.out.println("rel -> "+m.group("rel"));
    System.out.println("info -> "+m.group("info"));
    System.out.println("deactivated -> "+m.group("deactivated"));
}

输出:

type -> INFO
languageCode -> EN-GB
url -> http://www.whosebug.com
rel -> 1
info -> Text, that may contain all kind of chars.
deactivated -> false

编辑:Version2 正则表达式搜索 oneOfPossibleKeys=value 其中 value 结尾为:

  • , oneOfPossibleKeys=
  • 或后面有字符串结尾(由 $ 表示)。

代码:

String s = "type=INFO, languageCode=EN-GB, url=http://www.whosebug.com, ref=1, info=Text, that may contain all kind of chars., deactivated=false";

String[] possibleKeys = {"type","languageCode","url","ref","info","deactivated"};
String keysStrRegex = String.join("|", possibleKeys);
//above will contain type|languageCode|url|ref|info|deactivated

String regex = "(?<key>\b(?:"+keysStrRegex+")\b)=(?<value>.*?(?=, (?:"+keysStrRegex+")=|$))";
    // (?<key>\b(?:type|languageCode|url|ref|info|deactivated)\b)
    // =
    // (?<value>.*?(?=, (?:type|languageCode|url|ref|info|deactivated)=|$))System.out.println(regex);

Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(s);


while(m.find()){
    System.out.println(m.group("key")+" -> "+m.group("value"));
}

输出:

type -> INFO
languageCode -> EN-GB
url -> http://www.whosebug.com
ref -> 1
info -> Text, that may contain all kind of chars.
deactivated -> false