如何从Java中格式错误的字符串中获取属性和值

时间:2011-05-05 09:42:26

标签: java regex parsing

我需要从多个字符串中获取属性和值,例如:

<img src = "the source" class=class01 />
<img class=class02 src=folder/img.jpg />
<img class= "class01" / >

值中接受空格和斜杠,并且某些值用引号括起来,而不是全部。一些等号是间隔的。

我是新手,所以代码很乱,可能不是万无一失。

我的尝试:

//remove unnecessary spacing and "<img" and "/>"
str = str.replaceAll("/ >", "/>");
str = str.substring(4, str.length()-1);
str = str.replaceAll(" =", "=");
str = str.replaceAll("= ", "=");

//remove quotes
str = str.replaceAll("\"", "");

//creating a matcher and compiling the regex pattern is omitted, because I know how to do that using matcher.group();
regexSrc = "src=(.*?)($| class=)";
String srcString = matcherSrc.group(1);

regexClass = "class=(.*?)($| src=)";
String classString = matcherClass.group(1);

System.out.println("the source is: " + srcString);
System.out.println("the class is: " + classString);

任何建议如何做到这一点是一种更好的方式。

4 个答案:

答案 0 :(得分:2)

如果格式不正确的HTML代码,请使用JTidy进行清理,然后使用更简单的正则表达式或HTML解析器。

答案 1 :(得分:1)

您说您已经提取了<img>标记,并且您正在将其作为独立字符串进行处理。这使得工作更简单,但仍然需要处理很多复杂性。例如,您将如何处理此标记?

<img  foosrc="whatever" barclass=noclass src =
folder/img.jpg class   ='ho hum' ></img>

在这里你有:

  • 标记名称后面的多个空格
  • srcclass
  • 结尾的名称的属性
  • 第二个=
  • 之后的换行而不是空格
  • 属性名称与=
  • 之间的多个空格
  • 单引号,而不是属性值周围的双引号
  • 没有最终/,因为作者使用了一个带有结束标记的旧HTML样式图像标记,而不是XML样式的自闭标记。

...它和你提供的样本标签一样有效。也许知道你永远不必处理任何这些问题,但我们却没有。如果我们为您提供针对您的样本数据量身定制的正则表达式而不提及其他问题,我们是否真的帮助您?或者帮助遇到类似问题的其他人碰巧找到这个页面?

她然后去了:

String[] tags = { "<img src = \"the source\" class=class01 />",
                  "<img class=class02 src=folder/img02.jpg />",
                  "<img class= \"class03\" / >", 
                  "<img  foosrc=\"whatever\" barclass=noclass" +
                  "    class='class04' src =\nfolder/img04.jpg></img>" };

String regex = 
  "(?i)\\s+(src|class)\\s*=\\s*(?:\"([^\"]+)\"|'([^']+)'|(\\S+?)(?=\\s|/?\\s*>))";
Pattern p = Pattern.compile(regex);
int n = 1;
for (String tag : tags)
{
  System.out.printf("%ntag %d: %s%n", n++, tag);
  Matcher m = p.matcher(tag);
  while (m.find())
  {
    System.out.printf("%8s: %s%n", m.group(1),
        m.start(2) != -1 ? m.group(2) :
        m.start(3) != -1 ? m.group(3) :
        m.group(4));
  }
}

输出:

tag 1: <img src = "the source" class=class01 />
     src: the source
   class: class01

tag 2: <img class=class02 src=folder/img02.jpg />
   class: class02
     src: folder/img02.jpg

tag 3: <img class= "class03" / >
   class: class03

tag 4: <img  foosrc="whatever" barclass=noclass    class='class04' src =
folder/img04.jpg></img>
   class: class04
     src: folder/img04.jpg

这是一个更易读的正则表达式:

(?ix)   # ignore-case and free-spacing modes
\s+           # leading \s+ ensures we match the whole name
(src|class)   # the attribute name is stored in group1
\s*=\s*       # \s* = any number of any whitespace
(?:           # the attribute value, which may be...
   "([^"]+)"              # double-quoted (group 2)
 | '([^']+)'              # single-quoted (group 3)
 | (\S+?)(?=\s|/?\s*>)    # or not quoted (group 4)
)

答案 2 :(得分:0)

答案 3 :(得分:0)

正如Stephen C回答的那样,使用正则表达式通常不那么安全。它可能会让你陷入困境。

但是,至少对于给定的例子,这里可能会做你需要的东西:

 ([a-z]+) *= *"?((?:(?! [a-z]+ *=|/? *>|").)+)

rubular

您可能必须针对更多可能的输入进行测试,并且可能需要进行调整。

这里是java代码:

Pattern p = Pattern.compile("([a-z]+) *= *\"?((?:(?! [a-z]+ *=|/? *>|\").)+)", Pattern.DOTALL);
Matcher m = p.matcher(input);
while (m.find()){
    String key = m.group(1);
    String value = m.group(2);
    System.out.printf("%1s:%2s\n", key, value);
}