简体   繁体   English

重构这个简单方法的最有效方法是什么?

[英]What's the most effective way to refactor this simple method?

I have implemented a very simple method: 我实现了一个非常简单的方法:

private String getProfileName(String path) {
    String testPath = null;
    for (int i = 0; i < path.length(); i++) {
       testPath = path.substring(0, i);
          if ( testPath.endsWith("1") || testPath.endsWith("2") || testPath.endsWith("3") || testPath.endsWith("4") || testPath.endsWith("5") || testPath.endsWith("6") || testPath.endsWith("7") || testPath.endsWith("8") || testPath.endsWith("9") ) {
            break;
          }
    }
    return testPath.substring(0, (testPath.length() - 1));
}

I don't like the whole method because I think it's more complicated than necessary, especially the if condition. 我不喜欢整个方法,因为我认为它比必要的更复杂,尤其是if条件。

So I thought of a way to refactor this method. 所以我想到了一种重构这种方法的方法。 First I thought of using Regex to replace the if condition, but isn't regex a little bit too much for this simple case? 首先,我想到使用Regex来替换if条件,但对于这个简单的情况,是不是正则表达式有点太多了?

Any other ideas how to reafctor this? 任何其他想法如何重新审视这个?

Use this pattern with a matcher: 将此模式与匹配器一起使用:

"^[^1-9]*"

Example code: 示例代码:

private String getProfileName(String path) {
    Pattern pattern = Pattern.compile("^[^1-9]*");
    Matcher matcher = pattern.matcher(path);
    matcher.find();
    return matcher.group();
}

I think this is much easier to understand than your code. 我认为这比你的代码更容易理解。 It took me several minutes to work out your logic, and I had to run it to be sure. 我花了几分钟来计算你的逻辑,我必须运行它才能确定。 I think that with a regular expression it is quite clear what the code is doing. 我认为使用正则表达式很清楚代码在做什么。 If you wish you can compile the regular expression just once and reuse it by moving it to a static member of the class. 如果您希望可以只编译一次正则表达式并通过将其移动到类的静态成员来重用它。

Regular expressions have quite a bad stigma on Stack Overflow (mostly from people trying to use them to parse HTML, email addresses, URLs, and all sorts of other nasty inappropriate uses of regular expressions). 正则表达式对Stack Overflow有很大的耻辱(主要来自试图使用它们来解析HTML,电子邮件地址,URL以及各种其他令人讨厌的正则表达式的不当使用的人)。 But for this sort of task a regular expression is just fine. 但是对于这种任务,正则表达式就好了。

You may also wish to consider why you are omitting 0 and if that is a good idea. 您可能还想考虑为什么要省略0,如果这是个好主意。

Mine: 矿:

private String getProfileName(String path) {

    return path.split("[1-9]")[0];
}

Hope this will help you. 希望这会帮助你。

Explanation. 说明。 As Mark Byers said Split on digits (first version, second version ignores 0), and return the first element of the resulting array. 正如Mark Byers所说,数字上的Split(第一个版本,第二个版本忽略0),并返回结果数组的第一个元素。 But I think it won't fail if first argument is a digit (tested with jdk1.6.0_20). 但我认为如果第一个参数是一个数字(用jdk1.6.0_20测试),它不会失败。 It fails if all characters from the path are digits (by example "2223"). 如果路径中的所有字符都是数字(例如“2223”),则会失败。 You can use this version to avoid the error: 您可以使用此版本来避免错误:

private String getProfileName(String path) {

    String[] result = path.split("[1-9]");
    return result.length > 0 ? result[0] : "";
}

As you will se at String's split method javadocs , it takes an argument (a regular expression), you can use one of this: 正如您将在String的split方法javadocs中 ,它接受一个参数(正则表达式),您可以使用以下方法之一:

return path.split("[1-9]")[0]; //if you want to avoid 0
return path.split("\\d")[0]; //if you don't

IMHO: Using split method is better than other approaches if you are looking for improve your code readability, 恕我直言:如果您正在寻求提高代码可读性,使用split方法比其他方法更好,

Sure, you can refactor that using brute force...but why not use Apache Commons? 当然,你可以使用蛮力重构...但为什么不使用Apache Commons?

private String getProfileName(String path) {
    int index = StringUtils.indexOfAny(path, "123456789");
    if(index != -1) {
        return path.substring(0, index);
    }
    return path;
}

Other than regexs: 除了正则表达式:

private static String getProfileName(String path) {
    final int len = path.length();
    for (int i=0; i<len; ++i) {
       char c = path.charAt(i);
       if ('1' <= c && c <= '9') {
           return i==0 ? "" : path.substring(0, i-1); // Probably don't want that -1 !!
       }
    }
    return len==0 ? "" : path.substring(0, len-1);
}

Or perhaps, for Single Entry, Single Exit fans: 或者,对于Single Entry,Single Exit粉丝:

private static String getProfileName(String path) {
    final int len = path.length();
    int i=0;
    while (i != len && !isProfileTerminator(path.charAt(i))) {
    //Or (!(i == len || isProfileTerminator(path.charAt(i)))) {
       ++i;
    }
    return i==0 ? "" : path.substring(0, i-1);
}
private static boolean isProfileTerminator(char c) {
    return '1' <= c && c <= '9');
}

There are issues in the original code with strings that are empty or start with 1-9. 原始代码中存在问题,字符串为空或以1-9开头。

  private String getProfileName(String path)
  {
    int i;
    for (i = 0; i < path.length() && !Character.isDigit(path.charAt(i)); i++);
    return path.substring(0, i);
  }

I'd say go with the regex. 我会说与正则表达式一起去。 I can't think of a simpler way to refactor it. 我想不出更简单的重构方法。 I can probably think of more complicated ways, but I don't think you'd want that. 我可能会想到复杂的方法,但我不认为你会想要那样。

Here's a one-liner regex solution that is quite simple: 这是一个单行的正则表达式解决方案,非常简单:

private String getProfileName(String path) {
    return path.replaceFirst("(?s)\\d.*", "");
}

The pattern is \\d.* in Pattern.DOTALL mode, as embedded flag (?s) . Pattern.DOTALL模式下,模式为\\d.* ,作为嵌入式标志(?s) This will match a digit, and everything after it. 这将匹配一个数字,以及它之后的所有内容。 We want to remove this part, so we replace with the empty string. 我们想删除这部分,所以我们用空字符串替换。

Note that \\d includes 0 as well, so replace with [1-9] if that's really the specification. 请注意, \\d包含0 ,因此如果真的是规范,则替换为[1-9]

References 参考

You can create a method like this to put inside your if 您可以创建一个这样的方法放入if

private static boolean endsWith1to9(String a) {
        for(int i = 1; i <= 9; i++) {
            if(a.endsWith(String.valueOf(i))) {
                return true;
            }
        }
        return false;
    }

I think something like this will work. 我觉得这样的事情会起作用。 Someone correct me if I'm wrong. 如果我错了,有人会纠正我。

private String getProfileName(String path) {
    int i = 0;
    for(i = 0; i < path.length; ++i)
    {
        if(path.charAt(i) > '0' && path.charAt(i) <= '9') break;
    }
    return path.substring(0, i-1);
}

My try: 我的尝试:

/**
 * Numeric Register Optimized Search with Null Pointer Handling.
 * -> No use of Regex (per requirement). :)
 * -> No use of Character.isDigit() (NOTE: includes characters other than [0-9].)
 * -> Catch and Avoid NullPointerExceptions (Oops... review other methods above.)
 * -> Reduce for(...; test ; ...) to while(test) by variable declaration and ++off use.
 * -> Include ANDed test to avoid break call.
 * -> Cache "path.length" in local variable (e.g. CPU register)
 * -> Cache "path.charAt(off)" in local variable (e.g. CPU register)
 * -> Replace String.endsWith(...) Method with char < char Register Method.
 * -> Reuse path argument to avoid another internal object reference.
 * -> Avoid call to substring if [1-9] not found in path.
 * -> Single Entry/Single Exit Happy. :)
 * @return path null if passed null, otherwise valid value.
 */
private String getProfileName(String path) {
    if (path != null) {
        int off = -1, len = path.length;
        final char one = '1', nine = '9';
        char c;
        while (++off < len && (c = path.charAt(off)) < one && c > nine);
        if (off < len) {
            path = path.substring(0, off);
        }
    }
    return (path);
}
Cheers, loeJava 干杯,loeJava

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM