正規表現コンバータの文字クラスの入れ子の取り扱いを改善
This commit is contained in:
parent
5658679180
commit
937b387f77
|
@ -2,8 +2,7 @@ package jp.juggler.subwaytooter
|
|||
|
||||
import androidx.test.runner.AndroidJUnit4
|
||||
import jp.juggler.util.asciiPattern
|
||||
import jp.juggler.util.asciiPatternInternal
|
||||
import org.junit.Assert
|
||||
import jp.juggler.util.asciiPatternString
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
@ -40,22 +39,22 @@ class TestMisskeyMentionAndroid {
|
|||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testAsciiPatternInternal() {
|
||||
fun testasciiPatternString() {
|
||||
// \w \d \W \D 以外の文字は素通しする
|
||||
assertEquals("""ab\c\\""", """ab\c\\""".asciiPatternInternal())
|
||||
assertEquals("""[A-Za-z0-9_]""", """\w""".asciiPatternInternal())
|
||||
assertEquals("""[A-Za-z0-9_-]""", """[\w-]""".asciiPatternInternal())
|
||||
assertEquals("""[^A-Za-z0-9_]""", """\W""".asciiPatternInternal())
|
||||
assertEquals("""[0-9]""", """\d""".asciiPatternInternal())
|
||||
assertEquals("""[0-9:-]""", """[\d:-]""".asciiPatternInternal())
|
||||
assertEquals("""[^0-9]""", """\D""".asciiPatternInternal())
|
||||
assertEquals("""ab\c\\""", """ab\c\\""".asciiPatternString())
|
||||
assertEquals("""[A-Za-z0-9_]""", """\w""".asciiPatternString())
|
||||
assertEquals("""[A-Za-z0-9_-]""", """[\w-]""".asciiPatternString())
|
||||
assertEquals("""[^A-Za-z0-9_]""", """\W""".asciiPatternString())
|
||||
assertEquals("""[0-9]""", """\d""".asciiPatternString())
|
||||
assertEquals("""[0-9:-]""", """[\d:-]""".asciiPatternString())
|
||||
assertEquals("""[^0-9]""", """\D""".asciiPatternString())
|
||||
|
||||
// 文字セットの中の \W \D は変換できないので素通しする
|
||||
assertEquals("""[\W]""", """[\W]""".asciiPatternInternal())
|
||||
assertEquals("""[\D]""", """[\D]""".asciiPatternInternal())
|
||||
assertEquals("""[\W]""", """[\W]""".asciiPatternString())
|
||||
assertEquals("""[\D]""", """[\D]""".asciiPatternString())
|
||||
|
||||
// エスケープ文字の後に何もない場合も素通しする
|
||||
assertEquals("""\""", """\""".asciiPatternInternal())
|
||||
assertEquals("""\""", """\""".asciiPatternString())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -81,4 +80,24 @@ class TestMisskeyMentionAndroid {
|
|||
assertEquals(null, matchOrNull("\\d+", "0"))
|
||||
}
|
||||
|
||||
@Test fun test3(){
|
||||
// [] 空の文字セットはパースエラーになる。
|
||||
// val re1="""[]""".toRegex()
|
||||
|
||||
// 最低でも1文字を含む。
|
||||
assertEquals(true,"""[]]""".toRegex().matches("]"))
|
||||
|
||||
// 1文字あけた次からは閉じ括弧として扱われる。
|
||||
assertEquals(true,"""[ ]]""".toRegex().matches(" ]"))
|
||||
|
||||
// 閉じ括弧が単体で出たら文字クラスにならない。
|
||||
assertEquals(true,"""]""".toRegex().matches("]"))
|
||||
|
||||
// 閉じ括弧が足りないのはエラーになる。
|
||||
// val a="""[[ ]""".toRegex()
|
||||
|
||||
//
|
||||
assertEquals(true,"""[[ ]]][ ]""".toRegex().matches(" ] "))
|
||||
|
||||
}
|
||||
}
|
|
@ -40,55 +40,48 @@ fun String.asciiPatternString() : String {
|
|||
val dst = StringBuilder()
|
||||
dst.ensureCapacity(this.length)
|
||||
var escaped = false
|
||||
var insideSet = false
|
||||
for(c in this) {
|
||||
if(escaped) {
|
||||
escaped = false
|
||||
when(c) {
|
||||
'w' -> if(insideSet) {
|
||||
dst.append("A-Za-z0-9_")
|
||||
} else {
|
||||
dst.append("[A-Za-z0-9_]")
|
||||
}
|
||||
'd' -> if(insideSet) {
|
||||
dst.append("0-9")
|
||||
} else {
|
||||
dst.append("[0-9]")
|
||||
}
|
||||
var insideSet = 0
|
||||
var lastOpen =0
|
||||
for( i in this.indices){
|
||||
val c= this[i]
|
||||
when {
|
||||
escaped -> {
|
||||
escaped = false
|
||||
when(c) {
|
||||
'w' -> dst.append(if(insideSet>0) "A-Za-z0-9_" else "[A-Za-z0-9_]")
|
||||
'd' -> dst.append(if(insideSet>0) "0-9" else "[0-9]")
|
||||
|
||||
'W' -> {
|
||||
if(insideSet) {
|
||||
// 対応できないのでそのまま通す
|
||||
dst.append('\\')
|
||||
dst.append(c)
|
||||
} else {
|
||||
dst.append("[^A-Za-z0-9_]")
|
||||
}
|
||||
}
|
||||
// W,Dは文字セット内では対応できないのでそのまま通す
|
||||
'W' -> if(insideSet>0) dst.append('\\').append(c) else dst.append("[^A-Za-z0-9_]")
|
||||
'D' -> if(insideSet>0) dst.append('\\').append(c) else dst.append("[^0-9]")
|
||||
|
||||
'D' -> {
|
||||
if(insideSet) {
|
||||
// 対応できないのでそのまま通す
|
||||
dst.append('\\')
|
||||
dst.append(c)
|
||||
} else {
|
||||
dst.append("[^0-9]")
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
dst.append('\\')
|
||||
dst.append(c)
|
||||
else -> dst.append('\\').append(c)
|
||||
}
|
||||
}
|
||||
} else if(c == '\\') {
|
||||
escaped = true
|
||||
} else {
|
||||
dst.append(c)
|
||||
if(c == '[') {
|
||||
insideSet = true
|
||||
} else if(c == ']' && insideSet) {
|
||||
insideSet = false
|
||||
|
||||
c == '\\' -> escaped = true
|
||||
|
||||
else -> {
|
||||
dst.append(c)
|
||||
if(c == '[') {
|
||||
insideSet++
|
||||
lastOpen=i
|
||||
} else if(c == ']' && insideSet >0 && i > lastOpen+1) {
|
||||
insideSet--
|
||||
|
||||
// [] のようなカラの文字クラスは正規表現のエラーになる。
|
||||
// つまり文字クラスは最低でも1文字を含むので、
|
||||
// []] のような記述は ] のみを示す文字クラスになる。
|
||||
// [ ]] のような記述は 空白に続いて文字']'が出現する入力にマッチする。
|
||||
// 1文字あけた次からは閉じ括弧として扱われて、
|
||||
// 続いて開いてない時に登場した ] は普通の文字として扱われる。
|
||||
|
||||
// [[ABC][DEF]]は [ABCDEF]と同じ。入れ子になっている
|
||||
// JVMのPatternでは[A-Z&&[^D-F]]のような記述は「A-ZのうちD-F以外」と解釈される
|
||||
// ICUには [\p{Letter}&&\p{script=cyrillic}] や [\p{Letter}--\p{script=latin}]
|
||||
// JVMと同じような記述ができるかどうかは分からない。
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
package jp.juggler.subwaytooter
|
||||
|
||||
import jp.juggler.subwaytooter.api.entity.TootAccount
|
||||
import jp.juggler.util.asciiPattern
|
||||
import jp.juggler.util.asciiPatternInternal
|
||||
import jp.juggler.util.asciiPatternString
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.fail
|
||||
import org.junit.Test
|
||||
|
||||
class TestMisskeyMention {
|
||||
|
@ -27,22 +24,43 @@ class TestMisskeyMention {
|
|||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testAsciiPatternInternal() {
|
||||
fun testasciiPatternString() {
|
||||
// \w \d \W \D 以外の文字は素通しする
|
||||
assertEquals("""ab\c\\""", """ab\c\\""".asciiPatternInternal())
|
||||
assertEquals("""[A-Za-z0-9_]""", """\w""".asciiPatternInternal())
|
||||
assertEquals("""[A-Za-z0-9_-]""", """[\w-]""".asciiPatternInternal())
|
||||
assertEquals("""[^A-Za-z0-9_]""", """\W""".asciiPatternInternal())
|
||||
assertEquals("""[0-9]""", """\d""".asciiPatternInternal())
|
||||
assertEquals("""[0-9:-]""", """[\d:-]""".asciiPatternInternal())
|
||||
assertEquals("""[^0-9]""", """\D""".asciiPatternInternal())
|
||||
assertEquals("""ab\c\\""", """ab\c\\""".asciiPatternString())
|
||||
assertEquals("""[A-Za-z0-9_]""", """\w""".asciiPatternString())
|
||||
assertEquals("""[A-Za-z0-9_-]""", """[\w-]""".asciiPatternString())
|
||||
assertEquals("""[^A-Za-z0-9_]""", """\W""".asciiPatternString())
|
||||
assertEquals("""[0-9]""", """\d""".asciiPatternString())
|
||||
assertEquals("""[0-9:-]""", """[\d:-]""".asciiPatternString())
|
||||
assertEquals("""[^0-9]""", """\D""".asciiPatternString())
|
||||
|
||||
// 文字セットの中の \W \D は変換できないので素通しする
|
||||
assertEquals("""[\W]""", """[\W]""".asciiPatternInternal())
|
||||
assertEquals("""[\D]""", """[\D]""".asciiPatternInternal())
|
||||
assertEquals("""[\W]""", """[\W]""".asciiPatternString())
|
||||
assertEquals("""[\D]""", """[\D]""".asciiPatternString())
|
||||
|
||||
// エスケープ文字の後に何もない場合も素通しする
|
||||
assertEquals("""\""", """\""".asciiPatternInternal())
|
||||
assertEquals("""\""", """\""".asciiPatternString())
|
||||
|
||||
}
|
||||
|
||||
@Test fun test3(){
|
||||
// [] 空の文字セットはパースエラーになる。
|
||||
// val re1="""[]""".toRegex()
|
||||
|
||||
// 最低でも1文字を含む。
|
||||
assertEquals(true,"""[]]""".toRegex().matches("]"))
|
||||
|
||||
// 1文字あけた次からは閉じ括弧として扱われる。
|
||||
assertEquals(true,"""[ ]]""".toRegex().matches(" ]"))
|
||||
|
||||
// 閉じ括弧が単体で出たら文字クラスにならない。
|
||||
assertEquals(true,"""]""".toRegex().matches("]"))
|
||||
|
||||
// 閉じ括弧が足りないのはエラーになる。
|
||||
// val a="""[[ ]""".toRegex()
|
||||
|
||||
//
|
||||
assertEquals(true,"""[[ ]]][ ]""".toRegex().matches(" ] "))
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue