RegEx to match <a> html tags without special attribute

In Java, I need to match the <a> tags in a string that does not have an href attribute. For example, in the following line:

 text <a class="aClass" href="#">link1</a> text <a class="aClass" target="_blank">link2</a> text 

it must not match <a class="aClass" href="#">link1</a> (because it contains href), but it must match <a class="aClass" target="_blank">link2</a> (because it does not contain href).

I managed to create RegEx to match my tags:

 <a[^>]*>(.*?)</a> 

but i cant figure out how to remove tags using href

(I know I can use HTML parsers, etc., but I need to do this with RegEx.

+7
source share
4 answers

Description

Be careful with regular expressions, such as <abbr> <a[^>]* , as they will also match other valid html tags that start with a , such as <abbr> or <address> . Also, just looking for the existence of a href string is not good enough, since this string may be inside the value of another attribute or, for example, <a class="thishrefstuff"... , or part of another attribute, such as <a hreflang="en"...

This expression will be:

  • matches all anchor <a ... </a> tags that do not contain the href attribute.
  • This will result in the name of the tag a , not the tag that just starts with the letter a , like <address>
  • ignore attributes that also have the href substring embedded in the attribute name, for example, a valid hreflang='en' or compiled by Attributehref="some value" .
  • ignore all characters inside the value part of all correctly formatted attributes, such as bogus='href=""'

<a(?=\s|>)(?!(?:[^>=]|=(['"])(?:(?!\1).)*\1)*?\shref=['"])[^>]*>.*?<\/a>

enter image description here

Extended

  • <a(?=\s|>) match the open tag and provide the following after the tag name is either a space or a closing bracket, this forces the name a , not something else
  • (?! start a negative look ahead if we find href in this tag, then this type of tag is not the tag we are looking for
    • (?: start the group without capture to move through all the characters inside the tag
    • [^>=] correspond to all closing characters without tags, which do not allow the regular expression engine to leave the tag and not equal characters, which do not allow the engine to continue to blindly match all characters.
    • | or
    • =(['"]) matches an equal sign followed by an open double or single quote. The quote is captured in group 2, so it can be correctly paired later
    • (?:(?!\1).)* Match all characters that are not a closed quote, which corresponds to an open quote
    • \1 matches correct closed quote
    • )*? close the capturing group and repeat as often as needed until
    • \shref=['"] corresponding to the desired href attribute. \s and =["'] ensures that the attribute name is just href
    • ) close negative view
  • [^>]*>.*?<\/a> matches the entire line from open to close

Sample Java code:

Input text

<abbr>RADIO</abbr> text <a class="aClass" href="#">link1</a> text <a bogus='href=""' class="aClass" target="_blank">link2</a> text

the code

If you want to use this in the replace function to remove tags other than href-anchor, then simply replace all matches with nothing.

 import java.util.regex.Pattern; import java.util.regex.Matcher; class Module1{ public static void main(String[] asd){ String sourcestring = "source string to match with pattern"; Pattern re = Pattern.compile("<a(?=\\s|>)(?!(?:[^>=]|=(['\"])(?:(?!\\1).)*\\1)*?\\shref=['\"])[^>]*>.*?<\\/a> ",Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); Matcher m = re.matcher(sourcestring); int mIdx = 0; while (m.find()){ for( int groupIdx = 0; groupIdx < m.groupCount()+1; groupIdx++ ){ System.out.println( "[" + mIdx + "][" + groupIdx + "] = " + m.group(groupIdx)); } mIdx++; } } } 

Matches

 $matches Array: ( [0] => Array ( [0] => <a bogus='href=""' class="aClass" target="_blank">link2</a> ) [1] => Array ( [0] => ) ) 
+18
source

It seems strange to me that you will need to do this with a regular expression, but you can use a negative result.

 <a(?![^>]+href).*?>(.*?)</a> 
+4
source

I am not a java expert, but you can try something like this:

 String regex = new String("(?i)<a(?>[^h>]++|(?<! )h++|h++(?!ref\\s*+=))*>((?>[^<]++|<(?!/a>))*)</a>"); String replacement = new String("$1"); str.replaceAll(regex,replacement); 
0
source

One option is to first combine all the tags, and then use a regular expression to match those that are, so that you can ignore them. So your pseudo code will look like this:

 <a>tags = html.find(all<a>tags); for(String <a>tag : <a>tags){ if(<a>tag.isHref()) continue; //do proccessing } 
-one
source

All Articles