String indexOf UTF中的问题

时间:2017-02-15 13:59:57

标签: android string indexof

如果第一个包含第二个字符串,我试图在字符串中突出显示字符串。问题是当父字符串包含重音字符时,indexOf会返回第一个匹配错误的索引。 filterText 是要突出显示的字符串。例如。

@Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        View rowView = convertView;
        ViewHolder viewHolder;

        if (rowView == null) {
            LayoutInflater inflater = getLayoutInflater();
            rowView = inflater.inflate(R.layout.list_row_search, parent, false);
            // configure view holder
            viewHolder = new ViewHolder();
            viewHolder.tvName = (TextView) rowView.findViewById(R.id.tv_name);
            viewHolder.tvDescription = (TextView) rowView.findViewById(R.id.tv_description);
            rowView.setTag(viewHolder);

        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }


        viewHolder.tvName.setTypeface(tfBold);
        viewHolder.tvDescription.setTypeface(tfRegular);

        viewHolder.tvName.setText(getSpannedFromHtml(parkingList.get(position).getPostTitle()));
        viewHolder.tvDescription.setText(getSpannedFromHtml(parkingList.get(position).getPostSubTitle()));

        if(getUTF8Length(filterText) > 2){
            if(parkingList.get(position).getPostTitle().toLowerCase(Locale.getDefault()).contains(filterText)) {

                Log.d("AAA", "length 1: " + parkingList.get(position).getPostTitle().toLowerCase(Locale.getDefault()).length());
                Log.d("AAA", "length 2: " + getUTF8Length(parkingList.get(position).getPostTitle().toLowerCase(Locale.getDefault()).toString()));


                // Find all occurrences for the fist letter of filterText in Name
                for (int cont = -1; (cont = parkingList.get(position).getPostTitle().toLowerCase(Locale.US).indexOf(filterText.toLowerCase(Locale.US), cont + 1)) != -1; ) {
                    String str1 = "";
                    String str2 = "";
                    String str3 = "";

                    Log.d("AAA", "parkingList.get(position).getPostTitle().toLowerCase(Locale.US).indexOf(filterText.toLowerCase(Locale.US)): " + parkingList.get(position).getPostTitle().toLowerCase(Locale.US).indexOf(filterText.toLowerCase(Locale.US)));

                    Log.d("AAA", "parkingList.get(position).getPostTitle().toLowerCase(Locale.US).indexOf(filterText.toLowerCase(Locale.US): " + parkingList.get(position).getPostTitle().toLowerCase(Locale.US).indexOf(filterText.toLowerCase(Locale.US)));

                    if (cont > 0)
                        str1 = viewHolder.tvName.getText().subSequence(0, cont).toString();
                    str2 = viewHolder.tvName.getText().subSequence(cont, cont + getUTF8Length(filterText)).toString();
                    if ((cont + getUTF8Length(filterText)) < getUTF8Length(viewHolder.tvName.getText().toString()))
                        str3 = viewHolder.tvName.getText().subSequence(cont + getUTF8Length(filterText), getUTF8Length(viewHolder.tvName.getText().toString())).toString();

                    String highlilightedString = str1 + "<font color = #ef6c00>" + str2 + "</font>" + str3;
                    viewHolder.tvName.setText(getSpannedFromHtml(highlilightedString));
                }
            }

            if(parkingList.get(position).getPostSubTitle().toLowerCase(Locale.getDefault()).contains(filterText))
                // Find all occurrences for the fist letter of filterText in Description
                for(int cont = -1; (cont = parkingList.get(position).getPostSubTitle().toLowerCase(Locale.US).indexOf(filterText.toLowerCase(Locale.US), cont + 1)) != -1;){
                    String str1="";
                    String str2="";
                    String str3="";

                    if(cont > 0)
                        str1 = viewHolder.tvDescription.getText().subSequence(0, cont).toString();
                    str2 = viewHolder.tvDescription.getText().subSequence(cont, cont + filterText.length()).toString();
                    if((cont + filterText.length()) < viewHolder.tvDescription.getText().length() )
                        str3 = viewHolder.tvDescription.getText().subSequence(cont + filterText.length(), viewHolder.tvDescription.getText().length()).toString();

                    String highlilightedString = str1 + "<font color = #ef6c00>" + str2 + "</font>" + str3;
                    viewHolder.tvDescription.setText(getSpannedFromHtml(highlilightedString));
                }
            }

        return rowView;
    }

    /**
     *
     */
    private int getUTF8Length (String str) {
        int count = 0;

        for(int cont = 0, len = str.length(); cont < len; cont++){
            char ch = str.charAt(cont);
            if(ch <= 0x7F){
                count++;
            } else if(ch <= 0x7FF){
                cont+=2;
            } else if(Character.isHighSurrogate(ch)){
                count+=4;
                cont++;
            } else {
                count+=3;
            }
        }

        return count;
    }

问题是如果parkingList(position)包含例如字符串“PokémonShop”并且filterText包含“mon”,则indexOf方法返回9而不是4.如果评估的链是“Pokémon”,则以下日志是示例购买“和里面搜索的字符串是”mon“:

D/AAA: length 1: 17
D/AAA: length 2: 17
D/AAA: parkingList.get(position).getPostTitle().toLowerCase(Locale.US).indexOf(filterText.toLowerCase(Locale.US), 0): 9
D/AAA: parkingList.get(position).getPostTitle().toLowerCase(Locale.US).indexOf(filterText.toLowerCase(Locale.US): 9

1 个答案:

答案 0 :(得分:0)

这是因为你的 getUTF8Length()。它给你错误的长度值。请尝试下面的代码。 (您可能需要调整正则表达式以满足字符串要求。)

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:background="@drawable/list_item_palegrey_border_bottom"
                android:paddingLeft="10dp"
                android:paddingRight="10dp">

<Space
    android:layout_width="match_parent"
    android:layout_height="10dp"
    android:id="@+id/topSpace"/>

<android.support.percent.PercentRelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/milageHeader"
    android:layout_below="@id/topSpace"
    android:layout_marginBottom="5dp">

        <TextView
            app:layout_widthPercent="40%"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:layout_centerVertical="true"
            android:id="@+id/milageLabel"
            android:text="Milersättning:"/>

    <CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/milageCheckBox"
        android:layout_centerVertical="true"
        app:layout_marginLeftPercent="40%"/>

</android.support.percent.PercentRelativeLayout>


<android.support.percent.PercentRelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/milageContent"
    android:visibility="visible"
    android:layout_below="@id/milageHeader">

    <android.support.percent.PercentRelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/kilometersContainer"
        android:layout_marginBottom="10dp">

        <TextView
            app:layout_widthPercent="40%"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:id="@+id/kilometersLabel"
            android:text="Antal körda km:"
            android:layout_centerVertical="true"/>

        <EditText
            app:layout_widthPercent="30%"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:background="@drawable/border_square"
            android:theme="@style/AppTheme"
            android:id="@+id/kilometersEditText"
            android:layout_toRightOf="@+id/kilometersLabel"
            android:layout_toEndOf="@id/kilometersLabel"/>

    </android.support.percent.PercentRelativeLayout>

    <android.support.percent.PercentRelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/fromCityPlaceContainer"
        android:layout_below="@+id/kilometersContainer"
        android:layout_marginBottom="10dp">

        <TextView
            app:layout_widthPercent="40%"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:id="@+id/fromCityPlaceLabel"
            android:text="Från ort/plats:"
            android:layout_centerVertical="true"/>

        <EditText
            app:layout_widthPercent="30%"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:theme="@style/AppTheme"
            android:background="@drawable/border_square"
            android:id="@+id/fromCityPlaceEditText"
            android:layout_toRightOf="@+id/fromCityPlaceLabel"
            android:layout_toEndOf="@id/fromCityPlaceLabel"/>

    </android.support.percent.PercentRelativeLayout>

    <android.support.percent.PercentRelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/toCityPlaceContainer"
        android:layout_below="@+id/fromCityPlaceContainer">

        <TextView
            app:layout_widthPercent="40%"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:id="@+id/toCityPlaceLabel"
            android:text="Till ort/plats:"
            android:layout_centerVertical="true"/>

        <EditText
            app:layout_widthPercent="30%"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:id="@+id/toCityPlaceEditText"
            android:background="@drawable/border_square"
            android:theme="@style/AppTheme"
            android:layout_toRightOf="@+id/toCityPlaceLabel"
            android:layout_toEndOf="@id/toCityPlaceLabel"/>

    </android.support.percent.PercentRelativeLayout>

    <android.support.percent.PercentRelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/returnContainer"
        android:layout_below="@+id/toCityPlaceContainer">

        <TextView
            app:layout_widthPercent="40%"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:id="@+id/returnLabel"
            android:text="Tur och retur:"
            android:layout_centerVertical="true"/>

        <CheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:id="@+id/returnCheckBix"
            android:theme="@style/AppTheme"
            android:layout_toRightOf="@+id/returnLabel"
            android:layout_toEndOf="@id/returnLabel"/>

    </android.support.percent.PercentRelativeLayout>

    <android.support.percent.PercentRelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/purposeContainer"
        android:layout_below="@+id/returnContainer">

        <TextView
            app:layout_widthPercent="40%"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:id="@+id/purposeLabel"
            android:text="Syfte:"
            android:layout_centerVertical="true"/>

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:theme="@style/AppTheme"
            android:id="@+id/purposeEditText"
            android:background="@drawable/border_square"
            android:layout_toRightOf="@+id/purposeLabel"
            android:layout_toEndOf="@id/purposeLabel"/>

    </android.support.percent.PercentRelativeLayout>

</android.support.percent.PercentRelativeLayout>

<Space
    android:layout_width="match_parent"
    android:layout_height="10dp"
    android:layout_below="@id/milageContent"/>

示例输出:

private int getUTF8Length (String str) {
    int count = 0;

    List<String> characters=new ArrayList<String>();
    Pattern pat = Pattern.compile("[\\s*\\p{L}*]\\p{M}*");
    Matcher matcher = pat.matcher(str);
    while (matcher.find()) {
        characters.add(matcher.group());
    }

    count = characters.size();
    String s = characters.toString();
    Log.d("LogDebug", s);

    return count;
}

PS。此代码基于Java Unicode String length,正则表达式调整为字符串输入“神奇宝贝商店”。