1

This is sample input string for test

        <TextView
        android:id="@+id/txt_refer_invite"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/txt_refer_earn"
        android:layout_marginTop="8dp"
        android:fontFamily="@font/ms500"
        android:gravity="center"
        android:lineSpacingExtra="10sp"
        android:paddingLeft="16.7dp"
        android:paddingRight="16.7dp"
        android:text="@{data.description}"
        android:textColor="@color/color_858585"
        android:textSize="13.3sp"/>

    <TextView
        android:id="@+id/txt_refer_code"
        android:layout_width="200dp"
        android:layout_height="48dp"
        android:layout_below="@id/txt_refer_invite"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="22dp"
        android:fontFamily="@font/ms500"
        android:background="@drawable/bg_refer_code"
        android:gravity="center"
        android:text="@{data==null?``:`Invite code : `+data.referralCode}"
        android:textColor="#9c9c9c"
        android:textSize="14.3sp"/>

I want to find out every Textview without android:fontFamily using regex, I am not sure how to apply negative lookup properly. The regex i am using online Regex tester is

<TextView[\s\S]*?(?!fontFamily)[\s\S]*?>

But it return every textview (matches all textviews)

1 Answers1

0

The <TextView[\s\S]*?(?!fontFamily)[\s\S]*?> pattern matches <TextView, then any 0+ chars, as few as possible (thus, skipping at first), then asserts that there is no fontFamily substring immediately to the right of the current location, and then matches any 0+ chars as few as possible up to the first > (thus, the last [\s\S]*? is expanded all the way long to the end of match). The lookahead does not play any specific role (unless fontFamily goes right after <TextView which is never the case).

You need a tempered greedy token here if you want to use a regex for a one-off task like this:

<TextView(?:(?!fontFamily)[^>])*>
         ^^^^^^^^^^^^^^^^^^^^^^^ 

The (?:(?!fontFamily)[^>])* part will match any char but > that does not start a fontFamily substring, as many as possible occurrences, up to a >.

See the regex demo.

You may unwrap the token using negated character classes to make it more efficient:

<TextView[^f>]*(?:f(?!ontFamily)[^f>]*)*>
         *******************************

See another regex demo.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563