Как получить атрибуты и значения из плохо отформатированной строки в Java - PullRequest
3 голосов
/ 05 мая 2011

Мне нужно получить атрибуты и значения из нескольких строк, таких как эти:

<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 ]

2 голосов
/ 05 мая 2011

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

1 голос
/ 05 мая 2011

Вы говорите, что уже извлекли тег <img> и работаете с ним как с отдельной строкой. Это делает работу проще, но все еще есть много сложностей, с которыми приходится иметь дело. Например, как бы вы справились с этим тегом?

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

Здесь у вас есть:

  • более одного пробела после имени тега
  • атрибуты, имена которых только оканчиваются на src и class
  • перевод строки вместо пробела после второго =
  • более одного пробела между именем атрибута и =
  • одинарные кавычки вместо двойных кавычек вокруг значения атрибута
  • без окончательного /, поскольку автор использовал старый тег изображения в стиле 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)
)
0 голосов
/ 05 мая 2011

Как сказал Стивен С., для этого обычно не так безопасно использовать регулярные выражения.Это может привести к неприятностям.

Но вот кое-что, что может сделать то, что вам нужно, по крайней мере, для данного примера:

 ([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);
}
0 голосов
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...