Groovy 字符串

Groovy 字符串#

官方文档:http://www.groovy-lang.org/syntax.html

Groovy有java.lang.String和groovy.lang.GString两种字符串对象类型,具体如下

单引号字符串

单引号字符串是java.lang.String类型的,不支持占位符插值操作

def name = 'Groovy!'
def body = 'test $name'

println(body); //test $name,不是 test Groovy!

Groovy的字符串可以通过 "+" 直接拼接

assert 'groovy' == 'g' + 'roo' + 'vy';
println('ab\'' + 'f');  // ab'f

转义字符规则同Java一样

三重单引号字符串

三重单引号字符串也是java.lang.String类型的,不支持占位符插值操作,可以表示多行字符串

def str = '''line one
line two
line three'''

如果在换行之前加个\,则相当于没有换行

def str = '''\
line one aaa \n kkkk
line tow 2\
line three'''
println(str);

运行结果:

line one aaa 
 kkkk
line tow 2line three

双引号字符串

双引号字符串支持占位插值操作,如果双引号字符串中不包含占位符则是java.lang.String类型的,如果包含则是groovy.lang.GString类型的。

占位符可以用${}$来表示,${}用于替换一般字符串或表达式,$主要用于A.B的形式中

// ${}
def str1 = 'Groovy!'
def str2 = "hello ${str1}"
println(str2);  // hello Groovy!

def str3 = "the sum of 2 and 3 is ${2 + 3}"
println(str3);  // the sum of 2 and 3 is 5

// $
def str4 = "hello $str1"
println(str4);  // hello Groovy!

def map = ['name':'Tom', 'age':null, 'gender':null]
println("$map.name is $map.age years old, gender $map.gender"); // Tom is null years old, gender null

$ 只对a.b或a.b.c形式有效,如果表达式包含括号类似于方法调用、闭包的大括号或算术运算符是无效的。

def str = "wzx"	
println("my name length is ${str.length()}");  //my name length is 3

println("my name length is $str.length()");
//该代码运行抛出groovy.lang.MissingPropertyException异常,因为Groovy认为去访问num的toString的属性,所以异常

def closure = {"sum " + it};
def str1 = "2 + 3 = ${closure(5)}"
def str2 = "2 + 3 = $closure(5)"
println(str1);  // 2 + 3 = sum 5
println(str2);  // 2 + 3 = (5) 错误

注意,在表达式中访问属性前必须保证属性已经定义好(值为空也可以),如果使用了未定义的属性会抛出groovy.lang.MissingPropertyException异常

如果需要表示$ or ${}字符串,可以使用反斜杠\

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

插值闭包表达式的特殊情况

到目前为止,我们已经可以在${}占位符插值任意表达式。但是对于闭包有一个特殊情况和符号,占位符包含一个箭头${→}时,表达式实际上是一个闭包表达式,可以认为它是一个闭包前缀了一个美元符号:

//无参闭包
def strWithNoParmClosure = "2 + 3 = ${ -> 5}"  // 2 + 3 = 5
//带有一个 java.io.StringWriter 参数的闭包,可通过 << 操作符将内容传给参数
def strWithParmClosure = "1 + 2 != ${parm -> parm << 'six'}"  // 1 + 2 != six

以上两种都是占位符插值闭包的情况,看起来比单纯的表达式定义麻烦,但是闭包有一个特性:延迟运算(lazy evaluation)

def number = 1;
def eargeGString = "value = ${number}"
def lazyGString = "value = ${ -> number}"

assert eargeGString == "value = 1"
assert lazyGString == "value = 1"

number = 2;
assert eargeGString == "value = 1"
assert lazyGString == "value = 2"

对于普通插值表达式(eargeGString),其值实际在表达式创建时就被绑定了,如:

def num1 = 9, num2 = 11;
def fun(int p1, int p2){
    p1 + p2
}
def strWithParmClosure = "xxx ${fun(num1, num2)}";

println(strWithParmClosure);  // xxx 20

num2 = 20;
println(strWithParmClosure);  //xxx 20

但是对于有闭包的表达式,在每次GString转成String时闭包都会被调用。

插值闭包表达式中的闭包只允许有0或1个参数,否则运行时会抛异常

groovy> def strWithParmClosure = "2 + 3 != ${parm, parm2 -> (parm << 2) + (parm2 << 3)}"; 
groovy> println(strWithParmClosure); 

运行时异常:

groovy.lang.GroovyRuntimeException: Trying to evaluate a GString containing a Closure taking 2 parameters

GString & String hashCodes

String是不可变的,GString的String表示会根据插值变化,即使String和GString有相同的字符串,其hashCode也不同

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

所以应该避免使用GString作为Map key,例如:

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

assert m["a"] == null   //由于key的HashCode不同,所以取不到

三重双引号字符串

三重双引号字符串表现得像双引号字符串,另外它们是多行的

def name = 'Groovy'
def template = """
    Dear Mr ${name},\
    
    You're "the winner" of 'the lottery'!
    
    Yours sincerly,\
    
    Dave
    
    \"AAABBBB\\"
"""

assert template.contains("Groovy")
println(template);

运行结果:

...第一行为空行
    Dear Mr Groovy,    
    You're "the winner" of 'the lottery'!
    
    Yours sincerly,    
    Dave
    
    "AAABBBB\"

斜线字符串

使用/作为分隔符,Slashy字符串对于定义正则表达式和模式特别有用,因为没有必要转义反斜杠。

前斜线与单引号:

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

若在斜线字符串中要使用前斜线,需要用反斜线转义

def escapeSlash = /The character \/ is a forward \t slash  //用反斜线转义前斜线,而反斜线可直接写入,适用于正则式

assert escapeSlash == 'The character / is a forward \\t slash'  //单引号等其他字符串前斜线不需要转义

可表示多行字符串

def multilineSlashy = /one\
    two
    three/

assert multilineSlashy.contains('\n')  
println(multilineSlashy)

运行结果:

one    two
    three

支持插入占位符

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

assert interpolatedSlashy == /a blue car/
println(interpolatedSlashy)

需要注意的问题:

一个空的slashy字符串不能用双斜杠表示,因为它被Groovy解析器理解为一行注释,下面的断言实际上不会被编译,因为它被认为是一个未结束语句:

def color = ''
assert color == //

由于slashy字符串的设计主要是为了使regexp更容易,因此在GStrings中有一些错误,比如$(),在slashy字符串中可以使用

def slashy = /a $() car/
assert slashy == "a \$() car"  // GString中$需要转义

String比较

posted @ 2017-08-18 17:59  zxlc  阅读(1795)  评论(0编辑  收藏  举报