Groovy(二)-字符串

译文:Groovy Language Documentation

文本是由一连串的字符也就是字符串组成,Groovy让你实例化java.lang.String实体,和其他编程语言中的内插字符串GStrings (groovy.lang.GString)一样。

单引号字符串
单引号字符串是一系列被单引号包含的字符。

'a single quoted string'

注意:单引号字符串是简单的java.lang.String类型不支持内插

字符串连接
所有的Groovy 字符串都可以用+操作符进行连接。

assert 'ab' == 'a' + 'b'

三单引号字符串
三单引号字符串是一系列被三个单引号包含的字符。

'''a triple single quoted string'''

注意:三单引号字符串是简单的java.lang.String类型不支持内插
三单引号字符串是多行的字符串,你可以把字符串内容展开成跨行而不需要分出几部分,而且不需要连接符+和转义字符。

def aMultilineString = '''line one
line two
line three'''

如果你的代码有空格,比如在一个类的方法中,你的字符串可能包含有空白缩进。Groovy 的开发包中有方法String#stripIndent()可以去除这个空白缩进。并且提供了String#stripMargin()方法可以删除字符串开始位置指定的分隔符。

当我们创建如下字符串时:

def startingAndEndingWithANewline = '''
line one
line two
line three
'''

我们会发现字符串开头会包含\n字符,可以通过反斜号来转义开头的换行符:

def strippedFirstNewline = '''\
line one
line two
line three
'''
assert !strippedFirstNewline.startsWith('\n')

转义特殊字符
你可以使用反斜号\来转义单引号,避免完整的字符串被分割开了

'an escaped single quote: \' needs a backslash'

而且你可以使用双斜号\\来转义转义字符\

'an escaped escape character: \\ needs a double backslash'

一些特殊的字符也是用反斜号作为转义字符


特殊字符转义

Unicode码转义序列
对于在键盘中未出现的字符即中文,你可以使用unicode 转义序列:反斜号跟上u还有四个十六进制数字。

例如,欧洲货币符号可以如下展示:

'The Euro currency symbol: \u20AC'

双引号字符串
双引号字符串是被双引号包含的一系列字符。

"a double quoted string"

注意:当双引号字符串中没有插值表达式时,字符串的类型为java.lang.String,当双引号字符串中包含插值表达式时,字符串类型为groovy.lang.GString
想要转义双引号的话你可以使用反斜号\:"A double quote: ""

字符串插值(String interpolation)
除了单引号和三单引号字符串,所有的字符串都可以插入Groovy 表达式。插值实际就是替换字符串中的占位符,占位表达式是由${}包含起来或者是由$开头的.表达式,当GString 被传给一个带有String参数的方法 时,通过调用toString()方法,可以把占位符里面的表达式解析为真正的值。

这里我们就有引用了局部变量带有占位符的字符串

def name = 'Guillaume' // a plain string
def greeting = "Hello ${name}"

assert greeting.toString() == 'Hello Guillaume'

正如我们看到的,在这个带有算术表达式的例子中,这些Groovy 表达式都是正确的

def sum = "The sum of 2 and 3 equals ${2 + 3}"
assert sum.toString() == 'The sum of 2 and 3 equals 5'

注意:并不仅仅只有表达式可以放在${}占位符中,声明也是可以放在之中的,但是一个声明的值会是null,所以当有几个声明都被放在占位符中的话,最后一个声明必须返回一个有意义的值。例如:"The sum of 1 and 2 is equal to ${def a = 1; def b = 2; a + b}"是支持的,但是一个最佳实践是,在GString 占位符中通常是放一些简单的表达式。

除了${}占位符,我们也可以使用单独的$加上.表达式:

def person = [name: 'Guillaume', age: 36]
assert "$person.name is $person.age years old" == 'Guillaume is 36 years old'

但是只有这种格式例如a.b,a.b.c是对的,但是表达式包含圆括号像方法调用那样,还有大括号,或者算术操作也会是正确的,例如下面数字的定义:

def number = 3.14

下面的声明会抛出错误groovy.lang.MissingPropertyException,因为Groovy 认为,你将尝试调用这个数字的toString方法,但是是不存在的。

shouldFail(MissingPropertyException) {
    println "$number.toString()"
}

注意:你可以考虑将"$number.toString()"替换为"${number.toString}()"就可以被正常运行了

如果你想转义$${}占位符,你只要用反斜号\来转义$即可:

assert '${name}' == "\${name}"

特殊的插值闭包表达式
到目前为止,我们知道我们可以在${}占位符中插入任意的表达式,而且包含一种特殊的闭包表达式.当占位符带有箭头如:${→}, 那么这个表达式就是一个闭包表达式。你可以认为有一个$符号在大括号前面。

1.
def sParameterLessClosure = "1 + 2 == ${-> 3}" 
assert sParameterLessClosure == '1 + 2 == 3'
2.
def sOneParamClosure = "1 + 2 == ${ w -> w << 3}" 
assert sOneParamClosure == '1 + 2 == 3'

1.第一个例子是一个没有带参数的闭包
2.第二个例子是带了一个java.io.StringWriter类型参数的闭包,你可以用<<符号来添加内容,在这两个例子中,两个占位符都是嵌入闭包。

从表面上看,这似乎是一个冗长的定义插入表达式的方式,但是它有一个非常有趣的特性:延迟解析。
让我们看看下面这些例子:

1.
def number = 1 
def eagerGString = "value == ${number}"
def lazyGString = "value == ${ -> number }"

2.
assert eagerGString == "value == 1" 
3.
assert lazyGString ==  "value == 1" 
4.
number = 2 
5.
assert eagerGString == "value == 1" 
6.
assert lazyGString ==  "value == 2" 

1.我们定义了一个number变量1,然后将它插入GStrings中间,就像一个放在eagerGString中的表达式和一个放在lazyGString中间的闭包。
2.我们希望最终的字符串拥有跟eagerGString一样的字符串值1.
3.跟2一样
4.然后我们将数字number变为2
5.普通的插值表达式,在GString一创建的时候值就被确定了。
6.但是对于闭包表达式就不同了,每次number值变化,在它从GString 强转为String的时候,闭包表达式都会被调用,所以lazyGString 最终得到的值会发生变化。

注意:一个内嵌的闭包表达式不能包含多于一个参数,不然会报错。

跟java的协作
当一个方法(不管使用Groovy或者java实现)希望接收java.lang.String,但是我们传过去的却是groovy.lang.GString,那么toString()方法会自动且隐式地被调用。

String takeString(String message) {         
    assert message instanceof String              4
    return message                                5
}

def message = "The message is ${'hello'}"         1
assert message instanceof GString                 2

def result = takeString(message)                  3
assert result instanceof String
assert result == 'The message is hello'

1.创建一个GString 类型的变量
2.检查他是否是一个GString类型
3.将一个带有一个String类型参数的方法赋值给GString 类型的变量
4.takeString() 方法的签名说明了他的参数是String类型
5.我们能很明确分辨出参数是String 类型而不是GString 类型

GString and String hashCodes
虽然内插字符串可以替代普通的java字符串,但是在某些方面还是不同的:他们的哈希值不同。普通的java字符串是不可变的,但是由于内插值,GString字符串是可以改变的。设置对于相同的结果串,GString和普通字符串的哈希值都是不同的。

assert "one: ${1}".hashCode() != "one: 1".hashCode()

GString和普通字符串拥有不同的哈希值,用GString 作为map的key是不允许的。

def key = "a"
def m = ["${key}": "letter ${key}"]     1

assert m["a"] == null                   2  

1.这个map是用GString作为key来创建的
2.当我们打算用字符串取回map中的值的话,是查找不到的,因为普通字符串和GString字符串拥有不同的哈希值。

三双引号字符串
三双引号字符串和双引号字符串是类似的,只是三双引号字符串是支持多行的,和三单引号字符串是一样的。

def name = 'Groovy'
def template = """
    Dear Mr ${name},

    You're the winner of the lottery!

    Yours sincerly,

    Dave
"""
assert template.toString().contains('Groovy')

注意:双引号和单引号在三双引号字符串中都不需要转义字符。

Slashy (/)字符串
除了通常的引号字符串,Groovy还提供了Slashy 字符串,Slashy 字符串是以/作为分割符的。Slashy 字符串在定义常规表达式和模式的时候非常有用,因为他不需要转义字符。

def fooPattern = /.*foo.*/
assert fooPattern == '.*foo.*'

只有/是需要转义字符\来转义的:

def escapeSlash = /The character \/ is a forward slash/
assert escapeSlash == 'The character / is a forward slash'

Slashy字符串是可以多行的:

def multilineSlashy = /one
    two
    three/

assert multilineSlashy.contains('\n')

Slashy 字符串也是支持内插的:

def color = 'blue'
def interpolatedSlashy = /a ${color} car/

assert interpolatedSlashy == 'a blue car'

有一些小陷阱需要注意:
空的slashy字符串是不能用//来表示的,因为他会被理解为注释。这就是为什么下面的assert语句不会编译通过,因为这被理解为一个没有结束的语句。

assert '' == //

注意:slashy 字符串是设计来简化正则表达式的,GStrings 能跟它基本上一起使用,比如$()就可以放在slashy 字符串中。

Dollar slashy($/)字符串
Dollar slashy字符串是以$/开头/$结尾的多行GStrings字符串。这里的转义字符是$,它可以转义另外的$或者/,但是$/都不需要转义,除非在Dollar slashy字符串中的子串里需要放置GString占位序列,或者包含了闭合的 dollar slashy字符串,才需要用$进行转义。

def name = "Guillaume"
def date = "April, 1st"

def dollarSlashy = $/
    Hello $name,
    today we're ${date}.

    $ dollar sign
    $$ escaped dollar sign
    \ backslash
    / forward slash
    $/ escaped forward slash
    $$$/ escaped opening dollar slashy
    $/$$ escaped closing dollar slashy
/$

assert [
    'Guillaume',
    'April, 1st',
    '$ dollar sign',
    '$ escaped dollar sign',
    '\\ backslash',
    '/ forward slash',
    '/ escaped forward slash',
    '$/ escaped opening dollar slashy',
    '/$ escaped closing dollar slashy'
].every { dollarSlashy.contains(it) }

字符串总结表

总结表

字符
和java不同,Groovy 没有非常明确的字符类型,但是你能将Groovy中的字符串明确地转为字符,有三种不同的方式:

char c1 = 'A'                                 1
assert c1 instanceof Character

def c2 = 'B' as char                          2
assert c2 instanceof Character

def c3 = (char)'C'                            3
assert c3 instanceof Character

1.明确指定声明的字符为char类型
2.用as操作符强转
3.转化为char类型

注意:第一个选择是很有趣的,一个字符被一个变量持有,但是后面两种更有趣,一个字符被作为参数传给了一个方法调用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • 1.注释 1.1.单行注释 1.2.多行注释 1.3.GroovyDoc 1.4.Shebang line 2.关...
    勤劳的悄悄阅读 3,531评论 1 13
  • 官方文档 注释(Comments) 和Java一样,支持单行(使用//)、多行(/* */)和文档注释(使用/**...
    yjiyjige阅读 29,826评论 2 27
  • 一、字符串在C#中,字符串是一系列不可修改的Unicode字符,创建字符串后,就不能修改它。要创建字符串,最常用的...
    CarlDonitz阅读 1,264评论 0 2
  • 忘了是谁说过,即使在最灰暗的日子里也不能放弃自己,浮云之上有阳光,不管发生什么都请你抬起头,挺起胸,收拾好自己...
    修行的老鼠阅读 583评论 0 1