适用于多种模式的 Android SpannableStringBuilder

如何解决适用于多种模式的 Android SpannableStringBuilder

我为不同的实体(产品、房间、帖子和用户)设置了不同的屏幕。 所有这些都有不同的 ID,我用它来打开特定的屏幕,以尝试从通过 API 传递到相关屏幕/活动的 ID 参数加载数据。

我特别为产品、房间和帖子考虑的机制是在通知屏幕等上,我想发送编码或标记的字符串;例如下面的产品:

You have bid on <p244 24LED Lampshade />

为了匹配上面的内容我有一个正则表达式:

<p([0-9]*)\s(.*?)\/>(\s|$)

这是一个示例字符串:

 String dummyText = "Hi @dan we product test <p1337 product />" +
                        "\n how about <r123 Room name/> is a nice room" +
                        "\n what <t234 this post details more about it/> but you should " +
                        "\n #poprocks woah one #sad";

working OK with single instance but space is still messy at the end though

单次使用产品/帖子/房间似乎可以正常工作,但它会因编码/标记字符串的更多实例而混乱。

但就像我说的,有多个实例,如以下测试:

 String dummyText = "Hi @dan we product test <p1337 product /> and were more happy with <p53 car/> " +
                        "\n eh <r123 Room name/> is a nice room and <r233 dans house/> sucked while <r123 fun time/> was ok " +
//                        "\n what <t234 this post details more about it/> but you should " +
                        "\n <t234 view this as well/>" +
                        "\n #poprocks woah one #sad";

它搞砸了:

Multiple instances messes up

这是我的整个代码过程:

String dummyText = "Hi @dan we product test <p1337 product /> and were more happy with <p53 car/> " +
                        "\n eh <r123 Room name/> is a nice room and <r233 dans house/> sucked while <r123 fun time/> was ok " +
//                        "\n what <t234 this post details more about it/> but you should " +
                        "\n <t234 view this as well/>" +
                        "\n #poprocks woah one #sad";

                List<Pattern> patternsList = new ArrayList<>();
                patternsList.add(Pattern.compile(REGEX_NOTI_ROOMS)); //0
                patternsList.add(Pattern.compile(REGEX_NOTI_PRODUCTS)); //1
                patternsList.add(Pattern.compile(REGEX_NOTI_TWEETS)); //2
                patternsList.add(Pattern.compile(REGEX_NOTI_MENTION)); //3
                patternsList.add(Pattern.compile(REGEX_araBIC_N_NUM_HASHTAG)); //4
                holder.row_noti_messageTV.setText(makeSpannable(dummyText,patternsList));
                holder.row_noti_messageTV.setMovementMethod(new PkMovementMethod());

相关正则表达式在哪里:

    public static final String REGEX_NOTI_ROOMS ="<r([0-9]*)\\s(.*?)\\/>(\\s|$)";
    public static final String REGEX_NOTI_PRODUCTS ="<p([0-9]*)\\s(.*?)\\/>(\\s|$)";
    public static final String REGEX_NOTI_TWEETS ="<t([0-9]*)\\s(.*?)\\/>(\\s|$)";
    public static final String REGEX_araBIC_N_NUM_HASHTAG ="#(\\w*[0-9a-zA-Zء-ي٠-٩]+\\w*[0-9a-zA-Zء-ي٠-٩])";
    public static final String REGEX_NOTI_MENTION ="(?:^|\\s|$|[.])@[\\p{L}0-9_]*";

我的 makeSpannable 方法是:

    public SpannableStringBuilder makeSpannable(String rawText,List<Pattern> listofPatterns) {

//        StringBuffer sb = new StringBuffer();
        SpannableStringBuilder spannable = new SpannableStringBuilder(rawText);

        for(int i=0; i<listofPatterns.size(); i++)
        {
            Matcher matcher = null;
            if(i==0) //init only
                matcher = listofPatterns.get(i).matcher(rawText);
            else
                matcher = listofPatterns.get(i).matcher(spannable);

            while (matcher.find()) {
                showLogMessage("jsonParse","hit on iteration" + i + " group == " + matcher.group());
                if(i==3 || i == 4)
                {
                    try {
                        String abbr = matcher.group();
                        showLogMessage("jsonParse","loop[3 | 4 are normal] == " + i + " group(0) == " + abbr);

                        int start = matcher.start();
                        int end = matcher.end();

                        NotificationSpan ourSpan = new NotificationSpan(Color.BLUE,Color.RED,Color.TRANSPARENT,new IdTitleStore(abbr,abbr,abbr),NotificationAdapter.this);
                        spannable.setSpan(ourSpan,start,end,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                    } catch (Exception e) {
                        e.printstacktrace();
                    }
                }
                else if(i<=2) {
                    try {
                        String orgGroup = matcher.group();
                        // get the match
                        String abbr = matcher.group(2);
                        showLogMessage("jsonParse","loop == " + i + " group2 == " + abbr);

                        int startPoint = matcher.start();
                        int endPoint = matcher.end();

                        NotificationSpan ourSpan = new NotificationSpan(Color.RED,Color.BLUE,new IdTitleStore(matcher.group(1),orgGroup),NotificationAdapter.this);
                        Spannable spanText = new SpannableString(abbr);
                        spanText.setSpan(
                                ourSpan,abbr.length(),Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                        );

                        spannable.replace(startPoint,endPoint,spanText);


                    } catch (Exception e) {
                        e.printstacktrace();
                    }
                }

            }
        }

        return spannable;
    }

注意:NotificationSpan 是我用来存储组 (1) 的自定义跨度,因为它具有 ID,并且从组 (0) 中我可以通过点击推断它是否可能是要打开的帖子、产品或房间实体

任何反馈都应受到赞赏,即使它可以为我指明正确的方向。就像我的方法本身是根本错误的一样,请告诉我。

编辑:有人在评论中指出要从正则表达式中删除多余的 (\s|$),但它似乎什么也没做

我测试的 dummyString 的日志:

String dummyText = "Hi @dan we product test <p1337 product /> and were more happy with <p53 car/> " +
                        "\n eh <r123 Room name/> is a nice room and <r233 dans house/> sucked while <r123 fun time/> was ok " +
                        "\n what <t233 this post details more about it/> but you should " +
                        "\n <t234 view this as well/>" +
                        "\n #poprocks woah one #sad";

E/jsonParse: hit on iteration0 group(0) == <r123 Room name/>
E/jsonParse: hit on iteration0 group(0) == <r233 dans house/>
E/jsonParse: hit on iteration0 group(0) == <r123 fun time/>
E/jsonParse: hit on iteration1 group(0) == <p1337 product />
E/jsonParse: hit on iteration1 group(0) == <p53 car/>
E/jsonParse: hit on iteration2 group(0) == <t234 view this as well/>
E/jsonParse: hit on iteration3 group(0) ==  @dan
E/jsonParse: hit on iteration4 group(0) == #poprocks
E/jsonParse: hit on iteration4 group(0) == #sad

匹配器根本没有检测到第一个实例也很奇怪。 即

"\n what <t234 this post details more about it/> but you should "

在循环内匹配多个模式的逻辑本身可能完全有问题,但我似乎真的无法弄清楚。欣赏评论

EDIT EDIT*:我想我终于明白问题是什么了。在 replace 方法之后添加点它给了我两个建议,notify() 和 notifyAll(),这让我想知道这确实是基于多线程的操作(对其他人来说很明显,但是是的!)。所以多重循环实际上是问题所在。

由于替换调用会更新跨度本身,因此内部循环(而 mathcer.find())在匹配器上没有最新的跨度,它具有不同的/上一个跨度,如果只有发现了一个实例,但由于多个实例的开始和结束相距甚远,因此发生了一些意想不到的事情。在更新后的代码之后,我确实保留了 (\s|$) 以防万一产品/帖子/房间是字符串的结尾,因此它确实匹配而不是保持空白。

public SpannableStringBuilder makeSpannable(String rawText,List<Pattern> listofPatterns) {

        SpannableStringBuilder spannable = new SpannableStringBuilder(rawText);

        Matcher matcher = null;
        for(int i=0; i<listofPatterns.size(); i++)
        {
            matcher = listofPatterns.get(i).matcher(spannable.toString());

            while (matcher.find()) {
                showLogMessage("jsonParse","hit on iteration" + i + " group == " + matcher.group());
                if(i<=2) {
                    try {
                        String orgGroup = matcher.group();
                        // get the match
                        String abbr = matcher.group(2);
                        showLogMessage("jsonParse","span txt of iteration " + i + " going to be group2 == " + abbr);

                        int startPoint = matcher.start();
                        int endPoint = matcher.end();

                        NotificationSpan ourSpan = new NotificationSpan(Color.RED,endPoint-1,spanText);
                        matcher = listofPatterns.get(i).matcher(spannable);
                    } catch (Exception e) {
                        e.printstacktrace();
                    }
                }
                else {
                    try {
                        String abbr = matcher.group();
                        showLogMessage("jsonParse","span txt of iteration " + i + " going to be group(0) == " + abbr);

                        int start = matcher.start();
                        int end = matcher.end();

                        NotificationSpan ourSpan = new NotificationSpan(Color.BLUE,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                    } catch (Exception e) {
                        e.printstacktrace();
                    }
                }
            }
        }

        return spannable;

    }

附加说明:我认为最好解释一下为什么我将循环分成两部分来开始。原因很简单,我的 REGEX 的前 3 个我 100% 肯定有 group(2) 元素,我已经实现了点击 ID 机制。最后两个是普通的主题标签,并提及没有 group(2) 的标签

这是最终的工作外观,希望我不会遇到任何性能问题:

Code finally working after a lot of trial and suffering and errors.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?