Java 寻找被纤度计包裹的绳子的一部分

Java 寻找被纤度计包裹的绳子的一部分,java,regex,recursion,Java,Regex,Recursion,假设我有一个字符串,如下所示: String s="social network such as '''[http://www.facebook.com Facebook]''' , "+ "'''[http://www.twitter.com Twitter]''' and '''[http://www.tumblr.com tumblr]'''"; 我只需要检索'[和]'中的字符串 示例输出: http://www.facebook.com Facebook, http://www.twi

假设我有一个
字符串
,如下所示:

String s="social network such as '''[http://www.facebook.com Facebook]''' , "+
"'''[http://www.twitter.com Twitter]''' and '''[http://www.tumblr.com tumblr]'''";
我只需要检索
'[
]'
中的
字符串

示例输出:

http://www.facebook.com Facebook, http://www.twitter.com Twitter, http://www.tumblr.com   tumblr
我在使用
regex
时遇到了困难,所以我使用
递归来实现这个想法:

System.out.println(filter(s, "'''[",  "]'''"));
....

public static String filter(String s, String open, String close){   
  int start = s.indexOf(open);
  int end = s.indexOf(close);

  filtered = filtered + s.substring(start + open.length(), end) + ", ";
  s = s.substring(end + close.length(), s.length());

  if(s.indexOf(open) >= 0 && s.indexOf(close) >= 0)
     return filter(s, open, close);

  else
     return filtered.substring(0, filtered.length() - 2);
}

但在某些情况下,当我需要检索与
字符串
相同模式中的单词时,例如在
'
'
中,它会说字符串索引超出范围,因为
开始
结束
将保持相同的值


我怎样才能克服这个问题?
regex
是唯一的解决方案吗?

regex是正确的工具。使用和

确保将
打开
关闭
的任何特殊字符视为常规字符

m.group()
返回由
m.find()
匹配的最后一个
字符串中的组

m.find()
查找与正则表达式匹配的所有子字符串


非正则表达式解决方案: 注意:在这两种情况下,
end
都被分配
s.indexOf(close,start+1)
,使用and,这样即使
open
close
值相同,也不会发生错误

递归

public static String filter(String s, String open, String close){
    int start = s.indexOf(open);
    int end = s.indexOf(close, start + 1);

    //I took the liberty of adding "String" and renaming your variable
    String get = s.substring(start + open.length(), end);
    s = s.substring(end + close.length());

    if (s.indexOf(open) == -1){
        return get;
    }
    return get + ", " + filter(s, open, close);
}
public static String filter(String str, String open, String close){
    int open_length = open.length();
    int close_length = close.length();

    StringBuilder s = new StringBuilder(str);
    StringBuilder filtered = new StringBuilder();

    for (int start = s.indexOf(open), end = s.indexOf(close, start + 1); start != -1; 
        start = s.indexOf(open), end = s.indexOf(close, start + 1)){
        filtered.append(s.substring(start + open_length, end)).append(", ");
        s.delete(0, end + close_length);
    }

    return filtered.substring(0, filtered.length() - 2); //trailing ", "
}
与其立即添加
,“
,不如稍后处理它。另外,请注意
s.substring(end+close.length(),s.length())
s.substring(end+close.length())相同
另外,我觉得看
s.indexOf(…)==-1
比检查
=0更整洁

真正的问题在于你对待
过滤的
的方式。首先,您需要将
filtered
声明为type
String
。接下来,因为您正在执行递归,所以不应该连接到
筛选的
。这将使我们第一次看到
filtered
stringfiltered=s.substring(start+open.length(),end)+“,”。如果你修好了那条线,你的解决方案就行了

迭代的

public static String filter(String s, String open, String close){
    int start = s.indexOf(open);
    int end = s.indexOf(close, start + 1);

    //I took the liberty of adding "String" and renaming your variable
    String get = s.substring(start + open.length(), end);
    s = s.substring(end + close.length());

    if (s.indexOf(open) == -1){
        return get;
    }
    return get + ", " + filter(s, open, close);
}
public static String filter(String str, String open, String close){
    int open_length = open.length();
    int close_length = close.length();

    StringBuilder s = new StringBuilder(str);
    StringBuilder filtered = new StringBuilder();

    for (int start = s.indexOf(open), end = s.indexOf(close, start + 1); start != -1; 
        start = s.indexOf(open), end = s.indexOf(close, start + 1)){
        filtered.append(s.substring(start + open_length, end)).append(", ");
        s.delete(0, end + close_length);
    }

    return filtered.substring(0, filtered.length() - 2); //trailing ", "
}
这种迭代方法使用了
StringBuilder
,但是没有它也可以做到。它生成两个
StringBuilder
s,一个为空,另一个保存原始
String
的值。在
for
循环中:

  • int start=s.indexOf(打开),end=s.indexOf(关闭)
    获取索引的引用
  • 开始!=-如果
    s
    不包含
    open
  • start=s.indexOf(打开),end=s.indexOf(关闭)
    循环每次迭代后,再次查找索引

循环的内部将正确的子字符串附加到
finished
,并从另一个
StringBuilder

中删除附加的部分。正则表达式是用于此操作的正确工具。使用和

确保将
打开
关闭
的任何特殊字符视为常规字符

m.group()
返回由
m.find()
匹配的最后一个
字符串中的组

m.find()
查找与正则表达式匹配的所有子字符串


非正则表达式解决方案: 注意:在这两种情况下,
end
都被分配
s.indexOf(close,start+1)
,使用and,这样即使
open
close
值相同,也不会发生错误

递归

public static String filter(String s, String open, String close){
    int start = s.indexOf(open);
    int end = s.indexOf(close, start + 1);

    //I took the liberty of adding "String" and renaming your variable
    String get = s.substring(start + open.length(), end);
    s = s.substring(end + close.length());

    if (s.indexOf(open) == -1){
        return get;
    }
    return get + ", " + filter(s, open, close);
}
public static String filter(String str, String open, String close){
    int open_length = open.length();
    int close_length = close.length();

    StringBuilder s = new StringBuilder(str);
    StringBuilder filtered = new StringBuilder();

    for (int start = s.indexOf(open), end = s.indexOf(close, start + 1); start != -1; 
        start = s.indexOf(open), end = s.indexOf(close, start + 1)){
        filtered.append(s.substring(start + open_length, end)).append(", ");
        s.delete(0, end + close_length);
    }

    return filtered.substring(0, filtered.length() - 2); //trailing ", "
}
与其立即添加
,“
,不如稍后处理它。另外,请注意
s.substring(end+close.length(),s.length())
s.substring(end+close.length())相同
另外,我觉得看
s.indexOf(…)==-1
比检查
=0更整洁

真正的问题在于你对待
过滤的
的方式。首先,您需要将
filtered
声明为type
String
。接下来,因为您正在执行递归,所以不应该连接到
筛选的
。这将使我们第一次看到
filtered
stringfiltered=s.substring(start+open.length(),end)+“,”。如果你修好了那条线,你的解决方案就行了

迭代的

public static String filter(String s, String open, String close){
    int start = s.indexOf(open);
    int end = s.indexOf(close, start + 1);

    //I took the liberty of adding "String" and renaming your variable
    String get = s.substring(start + open.length(), end);
    s = s.substring(end + close.length());

    if (s.indexOf(open) == -1){
        return get;
    }
    return get + ", " + filter(s, open, close);
}
public static String filter(String str, String open, String close){
    int open_length = open.length();
    int close_length = close.length();

    StringBuilder s = new StringBuilder(str);
    StringBuilder filtered = new StringBuilder();

    for (int start = s.indexOf(open), end = s.indexOf(close, start + 1); start != -1; 
        start = s.indexOf(open), end = s.indexOf(close, start + 1)){
        filtered.append(s.substring(start + open_length, end)).append(", ");
        s.delete(0, end + close_length);
    }

    return filtered.substring(0, filtered.length() - 2); //trailing ", "
}
这种迭代方法使用了
StringBuilder
,但是没有它也可以做到。它生成两个
StringBuilder
s,一个为空,另一个保存原始
String
的值。在
for
循环中:

  • int start=s.indexOf(打开),end=s.indexOf(关闭)
    获取索引的引用
  • 开始!=-如果
    s
    不包含
    open
  • start=s.indexOf(打开),end=s.indexOf(关闭)
    循环每次迭代后,再次查找索引

循环的内部将正确的子字符串附加到
finished
,并从另一个
StringBuilder

中删除附加的部分。您可以非常轻松地使用字符串标记器来完成此操作。只需将整个字符串交给标记器,然后询问每个标记并检查它是否以分隔符开头。如果有,则将内容提取到结果集合中

字符串标记器版本的升级将更少,也不会像regent解决方案那样丑陋

以下是标记器版本:

public class TokenizerTest {

    @Test
    public void canExtractNamesFromTokens(){
        String openDelimiter = "'''[";
        String closeDelimiter = "]'''";
        String s="social network such as '''[http://www.facebook.com Facebook]''' , "+
            "'''[http://www.twitter.com Twitter]''' and '''[http://www.tumblr.com tumblr]'''";

        StringTokenizer t = new StringTokenizer(s);

        while (t.hasMoreElements()){
            String token = t.nextToken();
            if (token.startsWith(openDelimiter)){
                String url = token.substring(openDelimiter.length());
                token = t.nextToken();
                String siteName = token.substring(0, token.length()-closeDelimiter.length());
                System.out.println(url + " " + siteName);
            }
        }
   }
}

不知道这怎么会变得更简单或更干净。非常清楚代码在做什么。

您可以非常轻松地使用字符串标记器来实现这一点。只需将整个字符串交给标记器,然后询问每个标记并检查它是否以分隔符开头。如果有,则将内容提取到结果集合中

字符串标记器版本的升级将更少,也不会像regent解决方案那样丑陋

我在这里