29

好的,我想知道的是有没有一种方法可以用 Java 来做 Python 可以在下面做的事情......

string_sample = "hello world"

string_sample[:-1]
>>> "hello world"

string_sample[-1]
>>> "d"

string_sample[3]
>>> "l"

因为在我看来,Java 让你为相同的结果工作(我特别是每次都必须使用 2 个数字并且缺少 -1 来表示最后一个字符)

String string_sample = "hello world";

string_sample.substring(0,string_sample.length()-1);
>>> "hello world"

string_sample.substringstring_sample.length()];
>>> "d"

string_sample.(3,4);
>>> "l"

我还没有接触到 Java 中的数组/列表,所以真的希望 Java 有比这更容易的东西

编辑:将 string_sample[3] 的 'i' 修改为 'l'。好发现马龙!

4

8 回答 8

24

抱歉,Javasubstring不如 Python 的切片表示法灵活。

尤其:

  • 你可以给它一个开始,或者一个开始和结束,但不只是一个结束。(另外,没有步骤,但你不会错过那么多。)
  • 负指数是一个错误,而不是从最后开始计数。

您可以在此处查看文档。

但是,自己编写这个并不难:

public String slice_start(String s, int startIndex) {
    if (startIndex < 0) startIndex = s.length() + startIndex;
    return s.substring(startIndex);
}

public String slice_end(String s, int endIndex) {
    if (endIndex < 0) endIndex = s.length() + endIndex;
    return s.substring(0, endIndex);
}

public String slice_range(String s, int startIndex, int endIndex) {
    if (startIndex < 0) startIndex = s.length() + startIndex;
    if (endIndex < 0) endIndex = s.length() + endIndex;
    return s.substring(startIndex, endIndex);
}

将它们作为某些实用程序类的静态方法。

显然,这与 Python 并不完全相同,但它可能会处理您想要的所有情况,而且非常简单。如果您想处理其他边缘情况(包括诸如步进和传递切片等),您可以添加任何您想要的额外代码;没有一个是特别棘手的。


其他序列基本相同,但你会想要subSequence而不是substring. (您也可以subSequence在字符串上使用,因为 aStringCharSequence。)

数组实际上根本不是一种序列。您需要编写显式创建新数组并复制子数组的代码。但它仍然没有更复杂。


请注意,您可能想要查找已经为您完成此操作的库。此页面上的其他答案中至少有三个链接,这应该使您的搜索变得容易。:) (您可能仍然想自己做一次,只是为了了解这些库是如何工作的——但对于生产代码,我宁愿使用其他人已经弄清楚并测试了所有边缘情况的库,而不是重新实现轮子并在它们陷入单元测试或现场错误时处理它们......)

于 2013-06-25T21:27:11.020 回答
11

Java Boon Slice Notation 允许所有这些,以及字符串、列表、集合、映射等。

许多语言都有切片符号(Ruby、Groovy 和 Python)。Boon 将此添加到 Java 中。

Boon 具有三个 slc 运算符:slcslc(仅开始)和slcEnd

使用 Boon,您可以对字符串、数组(原始和通用)、列表、集合、树集、树图等进行切片。

切片符号 - 一个温和的介绍

boon 切片运算符的工作方式类似于 Python/Ruby 切片表示法:

Ruby 切片表示法

 arr = [1, 2, 3, 4, 5, 6]
 arr[2]    #=> 3
 arr[-3]   #=> 4
 arr[2, 3] #=> [3, 4, 5]
 arr[1..4] #=> [2, 3, 4, 5]

Python 切片表示法

string = "foo bar" 
string [0:3]  #'foo'
string [-3:7] #'bar'

以下内容来自一篇关于 Python 切片表示法的优秀文章:

切片符号的基础知识如下:

Python 切片表示法

     a[ index ]       # index of item
     a[ start : end ] # items start through end-1
     a[ start : ]     # items start through the rest of the array
     a[ : end ]       # items from the beginning through end-1
     a[ : ]           # a copy of the whole array

使用 Boon 的 Java 切片表示法:

      idx( index )         // index of item
      slc( a, start, end ) // items start through end-1
      slc( a, start )      // items start through the rest of the array
      slcEnd( a, end )     // items from the beginning through end-1
      copy( a )            // a copy of the whole array

slc代表切片 idx代表索引 slcEnd代表结束切片。 copy代表 well, err, um copy of course

要记住的关键点是结束值表示不在所选切片中的第一个值。因此,end 和 start 之间的区别在于所选元素的数量。另一个特点是 start 或 end 可能是负数,这意味着它从数组的末尾而不是开头开始计数。

因此:

具有负索引的 Python 切片表示法

         a[ -1 ]    # last item in the array
         a[ -2: ]   # last two items in the array
         a[ :-2 ]   # everything except the last two items

Java 负索引

         idx   ( a, -1)     // last item in the array
         slc   ( -2 )       // last two items in the array
         slcEnd( -2 )       // everything except the last two items

如果项目比你要求的少,Python 和 Boon 对程序员很友好:Python 不允许你越界,如果你这样做,它会返回更糟糕的空列表。Boon 遵循这一传统,但提供了一个选项来获取越界异常(稍后描述)。在 Python 和 Boon 中,如果你走远,你会得到长度,如果你试图低于 0,你会得到 0(计算后低于 0)。相反,Ruby 给你一个空指针(Nil)。Boon 复制 Python 风格,因为 Boon 的目标之一是避免返回 null(你得到一个异常,Option)。(Boon 有第二个称为 zlc 的运算符,它会抛出一个越界索引异常,但大多数人应该使用 slc。)

例如,如果你要求 slcEnd(a, -2) (a[:-2]) 并且 a 只包含一个元素,你会得到一个空列表而不是错误。有时您更喜欢错误,而使用 Boon,您可以选择。

更多切片

这里有一些基本的 Java 类型,列表、数组、蔬菜、原始字符数组和原始字节数组。

在 Boon 中声明要使用的变量

//Boon works with lists, arrays, sets, maps, sorted maps, etc.
List<String> fruitList;
String [] fruitArray;
Set<String> veggiesSet;
char [] letters;
byte [] bytes;
NavigableMap <Integer, String> favoritesMap;
Map<String, Integer> map;

//In Java a TreeMap is a SortedMap and a NavigableMap by the way.

Boon 带有帮助方法,可以让您轻松创建列表、集合、映射、并发映射、排序映射、排序集合等。帮助方法有 safeList、list、set、sortedSet、safeSet、safeSortedSet 等。其思想是让 Java 感觉更像列表和地图是内置在类型中的。

初始化集合、列表、字符串数组、字符数组和字节数组

veggiesSet  =  set( "salad", "broccoli", "spinach");
fruitList   =  list( "apple", "oranges", "pineapple");
fruitArray  =  array( "apple", "oranges", "pineapple");
letters     =  array( 'a', 'b', 'c');
bytes       =  array( new byte[]{0x1, 0x2, 0x3, 0x4});

甚至还有创建地图和排序地图的方法,称为 map、sortedMap、safeMap(并发)和 sortedSafeMap(并发)。这些主要是因为 Java 没有用于列表、映射等的文字。

Java:使用 map 运算符生成 SortedMap 和 Map

 favoritesMap = sortedMap(
      2, "pineapple",
      1, "oranges",
      3, "apple"
 );


 map =    map (
    "pineapple",  2,
    "oranges",    1,
    "apple",      3
 );

您可以使用 idx 运算符对地图、列表、数组等进行索引。

Java:使用 Boon Java idx 运算符获取索引处的值

 //Using idx to access a value.

 assert idx( veggiesSet, "b").equals("broccoli");

 assert idx( fruitList, 1 ).equals("oranges");

 assert idx( fruitArray, 1 ).equals("oranges");

 assert idx( letters, 1 ) == 'b';

 assert idx( bytes, 1 )      == 0x2;

 assert idx( favoritesMap, 2 ).equals("pineapple");

 assert idx( map, "pineapple" )  == 2;

idx 运算符也适用于负索引。

Java:使用带负值的 idx 运算符

         //Negative indexes

          assert idx( fruitList, -2 ).equals("oranges");

          assert idx( fruitArray, -2 ).equals("oranges");

          assert idx( letters, -2 ) == 'b';

          assert idx( bytes, -3 )   == 0x2;

Ruby、Groovy 和 Python 都有这个特性。现在您也可以在 Java 中使用它!Java 版本 (Boon) 与原始数组一起使用,因此您不会得到auto-boxing

Ruby 和 Python 没有的东西是 SortedSets 和 SortedMaps 的切片表示法。您可以使用切片表示法在 Java 中搜索已排序的映射和已排序的集合

切片符号适用于已排序的地图和已排序的集合。

这是一个将几个概念放在一起的示例。

          set = sortedSet("apple", "kiwi", "oranges", "pears", "pineapple")

          slcEnd( set, "o" )      //returns ("oranges", "pears", "pineapple")
          slc( set, "ap", "o" )   //returns ("apple", "kiwi"),
          slc( set, "o" )         //returns ("apple", "kiwi")

您实际上是在对排序地图进行切片,而排序集是排序之间的查询。“pi”后面是什么项目?

          after(set, "pi") //pineapple

在菠萝之前?

          before(set, "pi")

好吧,让我们一步一步来……

  NavigableSet<String> set =
          sortedSet("apple", "kiwi", "oranges", "pears", "pineapple");

  assertEquals(

          "oranges", idx(set, "ora")

  );

记住:TreeSet 实现了 NavigableSet 和 SortedSet。

这是来自我的博客......

http://rick-hightower.blogspot.com/2013/10/java-slice-notation-to-split-up-strings.html

有更多的例子。

我从这个关于 Python 切片的讨论中得出了一些措辞。

解释 Python 的切片符号

这是 Boon 项目链接:

https://github.com/RichardHightower/boon

现在让我们继续 SLICE!

我们可以使用以下命令查找以 'o' 开头的集合中的第一个水果:

idx(set, "o")

这是我们之前创建的一组水果(set 是一个 TreeSet,其中包含“apple”、“kiwi”、“oranges”、“pears”、“pineapple”)。

      assertEquals(

          "oranges", idx(set, "o")

      );

我们找到了橘子!

又是这样,但这次我们要搜索以“p”开头的水果,即 idx(set, "p")。

      assertEquals(
          "pears",
          idx(set, "p")
      );

是的!我们找到了梨!

以“pi”开头的水果怎么样,比如“pineapple” - idx(set, "pi")

  assertEquals(
          "pineapple",
          idx(set, "pi")
  );

您也可以要求在另一个项目之后的项目。“pi”后面是什么?之后(设置,“pi”)

  assertEquals(

          "pineapple",
          after(set, "pi")

  );

“菠萝”在项目“pi”之后。顺便说一下,after 和 idx 是一样的。那我为什么要加一个after呢?所以我可以有一个以前!:) 如果您想知道“pi”之前的内容怎么办?

之前(设置,“pi”)

  assertEquals(

          "pears",
          before(set, "pi")

  );

“ap”和“o”之间的所有水果怎么样?正如我所承诺的,有切片符号!

slc(设置,“ap”,“o”)

  assertEquals(

          sortedSet("apple", "kiwi"),
          slc(set, "ap", "o")

  );

“o”之后的所有水果怎么样?

slc(设置,“o”)

  assertEquals(

          sortedSet("apple", "kiwi"),
          slc(set, "o")

  );

所以“o”之后的所有水果都是“apple”和“kiwi”。

直到“o”的所有水果怎么样?(slcEnd 阅读它,因为我正在切掉结尾。)

slcEnd(设置,“o”)

  assertEquals(

          sortedSet("oranges", "pears", "pineapple"),
          slcEnd(set, "o")
  );

因此,直到并包括“o”在内的所有水果都是“橙子”、“梨”和“菠萝”。

安全切片列表之类的东西

如果索引超出范围,这些运算符会引发异常:

使用 Boon 的 Java Slice Notation 如下:

      ix( index )         // index of item
      zlc( a, start, end ) // items start through end-1
      zlc( a, start )      // items start through the rest of the array
      zlcEnd( a, end )     // items from the beginning through end-1

zlc代表零容忍切片 ix代表零容忍索引 zlcEnd代表零容忍结束切片。 copy代表 well, err, um copy of course

男孩和女孩……请记住始终对您不认识的对象进行安全切片。

也适用于 Primitives,因此没有自动装箱

索引原语

 byte[] letters =
      array((byte)'a', (byte)'b', (byte)'c', (byte)'d');

 assertEquals(
      'a',
      idx(letters, 0)
 );


 assertEquals(
      'd',
      idx(letters, -1)
 );


 assertEquals(
      'd',
      idx(letters, letters.length - 1)
 );

 idx(letters, 1, (byte)'z');

 assertEquals(
      (byte)'z',
      idx(letters, 1)
 );

len 和 idx 方法是通用运算符,它们适用于列表、数组、集合、映射等。

len给我一个类似数组、类似列表、类似地图的东西的长度。 idx在类似数组、类似列表、类似地图的事物中的“索引”位置给我项目。

HOME MC弦片!

以下是 Boon Java 字符串切片的一些示例

  String letters = "abcd";

  boolean worked = true;

  worked &=

          idx(letters, 0)  == 'a'
                  || die("0 index is equal to a");



  worked &=

          idx(letters, -1)  == 'd'
                  || die("-1 index is equal to a");

另一种表示 idx(letters, -1) == 'd' 的方式是 idx(letters, letters.length() - 1) == 'd'!我更喜欢较短的方式!

  worked &=

          idx(letters, letters.length() - 1) == 'd'
                   || die("another way to express what the -1 means");


  //We can modify too
  letters = idx(letters, 1, 'z');

  worked &=

          idx(letters, 1) == 'z'
                  || die("Set the 1 index of letters to 'z'");


  worked &= (
          in('a', letters) &&
          in('z', letters)
  ) || die("'z' is in letters and 'a' is in letters");

切片切片宝贝!

  letters = "abcd";

  worked &=
          slc(letters, 0, 2).equals("ab")
              || die("index 0 through index 2 is equal to 'ab'");



  worked &=
          slc(letters, 1, -1).equals("bc")
                  || die("index 1 through index (length -1) is equal to 'bc'");


  worked &=
          slcEnd(letters, -2).equals("ab")
                  || die("Slice of the end of the string!");


  worked &=
          slcEnd(letters, 2).equals("ab")
                  || die("Vanilla Slice Slice baby!");

在我的 5.0 中滚动,把我的抹布从上到下,这样我的头发就可以吹了!切切宝贝!!!

于 2013-10-23T07:57:50.337 回答
8

Apachecommons-lang在 StringUtils对此有一些支持:

从指定的 String 中获取子字符串,避免异常。

负起始位置可用于从字符串末尾开始 n 个字符

不过,您仍然必须使用显式开始索引。

于 2013-06-25T21:30:33.203 回答
1

您可以轻松编写这样的方法,请记住从字符串的长度中减去负索引以获得正确的索引。

public String slice(String s, int start) {
   if (start < 0) start = s.length() + start; 

   return s.substring(start);
}
于 2013-06-25T21:28:21.040 回答
1

使用substring

class Main
{
  public static void main (String[] args) throws java.lang.Exception
  {
     String s = new String("hello world");
     System.out.println(s.substring(0, s.length()));
     System.out.println(s.substring(s.length() - 1, s.length()));
     System.out.println(s.substring(3, 4));
  }
}

charAt

System.out.println(s.charAt(s.length() - 1));
System.out.println(s.charAt(3));

Java 不是 python,因此应避免使用负索引以保持一致性。但是,您可以创建一个简单的转换函数。

于 2013-06-25T21:29:19.103 回答
0

我认为没有这样的 Java 字符串库提供与 python 提供的完全相同的东西。可能你能做的最好的事情就是建立一个新的类来提供你需要的功能。由于 java 中的String是一个 final 类,你不能从它扩展一个类,你需要使用组合。例如:

public class PythonString {
  protected String value;
  public PythonString(String str) {
    value = new String(str);
  }

  public char charAt(int index) {
    if (index < 0) {
      return value.charAt(value.length() + index);
    }
    return value.charAt(index);
  }

  ....

}

另一种选择是创建一个静态字符串库。

于 2013-06-25T21:24:56.653 回答
0

我为此创建了一个简单的库,称为JavaSlice,它提供了一种以与 Python 类似的方式访问 Java 中的字符串、列表或数组切片的统一方法。

所以你的例子可以简单地写成这样:

    String sample = "hello world";

    System.out.println(slice(sample, 0, -1)); // "hello worl"
    System.out.println(slice(sample, -1)); // 'd'
    System.out.println(slice(sample, 3)); // 'l'
于 2013-07-24T15:51:58.163 回答
-1

简单的回答,不,没有。字符串在两种语言中都是不可变的。字符串在内部存储为字符数组,因此在 Python 中使用子字符串和使用括号本质上是做同样的事情。Java 不支持运算符重载,因此无法将该功能赋予该语言。使用子字符串还不错。你不应该经常这样做。如果您经常编写帮助函数以简化使用,您总是可以编写帮助函数。

于 2013-06-25T21:27:21.433 回答