我必须在这里处理由脏设计引起的问题。我得到一个字符串列表,并希望解析它的属性。不幸的是,我无法更改创建这些String的源。
示例:
String s = "type=INFO, languageCode=EN-GB, url=http://www.stackoverflow.com, ref=1, info=Text, that may contain all kind of chars., deactivated=false"
现在我要提取属性type
,languageCode
,url
,ref
,info
和deactivated
。
这里的问题是字段info
,其文本不受引号的限制。此字段中也可能出现逗号,因此我无法在字符串末尾使用逗号来查找结束的位置。
另外,这些字符串并不总是包含所有属性。始终存在type
,info
和deactivated
,其余为可选。
有什么建议我可以解决这个问题吗?
答案 0 :(得分:4)
一种可能的解决方案是在输入中搜索=
个字符,然后将其前面的单个字作为字段名称 - 似乎所有字段名称都是单个字(无空格)。如果是这种情况,那么您可以将=
之后的所有内容,直到下一个字段名称(将,
分开)作为值。
这假设该值不能包含=
。
修改强>
作为处理嵌入式=
的一种可能方法,您可以查看它前面的单词是否是您已知的字段名称 - 如果不是,您可以将=
视为嵌入字符而不是运营商。但是,这假定您有一组固定的已知字段(其中一些可能并不总是出现)。如果您知道字段名称区分大小写,则可以放宽此假设。
答案 1 :(得分:2)
假设元素的顺序是固定的,你可以使用像这样的正则表达式编写解决方案
String s = "type=INFO, languageCode=EN-GB, url=http://www.stackoverflow.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.stackoverflow.com
rel -> 1
info -> Text, that may contain all kind of chars.
deactivated -> false
编辑:版本2 正则表达式搜索oneOfPossibleKeys=value
以value
结尾的地方:
, oneOfPossibleKeys=
$
表示)。代码:
String s = "type=INFO, languageCode=EN-GB, url=http://www.stackoverflow.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.stackoverflow.com
ref -> 1
info -> Text, that may contain all kind of chars.
deactivated -> false
答案 2 :(得分:1)
您可以使用正则表达式捕获所有&#34;固定的&#34;分组并使用Cat B.
的剩余部分。如果["Cat B.", 3, 19, 0, 1, 21],
部分包含info
或info
字符,这甚至可以使用。这是一个简单的例子(使用Python,但这应该不是问题......)。
,
如果这些元素中的任何一个是可选的,您可以在这些组之后添加=
,并使逗号可选。如果订单可能不同,那么它就更复杂了。在这种情况下,不是使用一个RegEx一次捕获所有内容,而是使用多个RegEx来捕获各个属性,然后在匹配下一个属性之前删除(替换为>>> p = r"(type=[A-Z]+), (languageCode=[-A-Z]+), (url=[^,]+), (ref=\d), (info=.+?), (deactivated=(?:true|false))"
>>> s = "type=INFO, languageCode=EN-GB, url=http://www.stackoverflow.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.stackoverflow.com',
'ref=1',
'info=Text, that may contain all kind of chars, even deactivated=true.',
'deactivated=false')
)字符串中的那些属性。最后,匹配?
。
进一步考虑,鉴于这些属性可能有任何顺序,从一个关键字到下一个关键字捕获所有内容可能更有希望,无论其实际内容如何,与Pshemo的解决方案非常相似:< / p>
''
但是,这也可能在一些非常模糊的情况下失败,例如:如果info
属性包含keys = "type|languageCode|url|ref|info|deactivated"
p = r"({0})=(.+?)(?=\, (?:{0})=|$)".format(keys)
matches = re.findall(p, s)
之类的内容,包括逗号。然而,似乎没有办法解决这些含糊之处。如果您有一个类似info
的字符串,它是否包含一个', ref=foo'
属性,或三个,或者根本没有?