这种有条件的正则表达式是最有效的吗?

时间:2016-06-28 20:45:46

标签: php regex conditional

我将用PHP演示我的例子。我正在测试引用的字符串是否正确关闭(例如,如果以dq开头,引用的字符串必须以双引号关闭)。引号之间必须至少有1个字符,并且引号之间的字符集不能包含相同的开始/结束引号字符。例如:

$myString = "hello";// 'hello' also good but "hello' should fail

if (preg_match("/^(\")?[^\"]+(?(1)\")|(\')?[^\']+(?(1)\')$/", $myString)) {
    die('1');
} else {
    die('2');
}

// The string '1' is outputted which is correct

我是条件正则表达式的新手,但对我来说,似乎我不能使preg_match()更简单。这是对的吗?

2 个答案:

答案 0 :(得分:2)

要做到这一点,不需要使用“条件功能”。但是你需要检查字符串从开始到结束(换句话说,你不能只检查字符串的一部分)

E/AndroidRuntime: FATAL EXCEPTION: GLThread 19364
              Process: com.davidheadrick.mariogame, PID: 12739
              com.badlogic.gdx.utils.GdxRuntimeException: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load dependencies of asset: mario_music.ogg
                  at com.badlogic.gdx.assets.AssetManager.handleTaskError(AssetManager.java:570)
                  at com.badlogic.gdx.assets.AssetManager.update(AssetManager.java:375)
                  at com.badlogic.gdx.assets.AssetManager.finishLoading(AssetManager.java:396)
                  at com.davidheadrick.mariogame.MarioGame.create(MarioGame.java:38)
                  at com.badlogic.gdx.backends.android.AndroidGraphics.onSurfaceChanged(AndroidGraphics.java:275)
                  at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1550)
                  at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1278)
               Caused by: com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load dependencies of asset: mario_music.ogg
                  at com.badlogic.gdx.assets.AssetLoadingTask.handleAsyncLoader(AssetLoadingTask.java:121)
                  at com.badlogic.gdx.assets.AssetLoadingTask.update(AssetLoadingTask.java:90)
                  at com.badlogic.gdx.assets.AssetManager.updateTask(AssetManager.java:498)
                  at com.badlogic.gdx.assets.AssetManager.update(AssetManager.java:373)
                  at com.badlogic.gdx.assets.AssetManager.finishLoading(AssetManager.java:396) 
                  at com.davidheadrick.mariogame.MarioGame.create(MarioGame.java:38) 
                  at com.badlogic.gdx.backends.android.AndroidGraphics.onSurfaceChanged(AndroidGraphics.java:275) 
                  at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1550) 
                  at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1278) 
               Caused by: com.badlogic.gdx.utils.GdxRuntimeException: com.badlogic.gdx.utils.GdxRuntimeException: Error loading audio file: mario_music.ogg
              Note: Internal audio files must be placed in the assets directory.
                  at com.badlogic.gdx.utils.async.AsyncResult.get(AsyncResult.java:46)
                  at com.badlogic.gdx.assets.AssetLoadingTask.handleAsyncLoader(AssetLoadingTask.java:119)
                    ... 8 more
               Caused by: com.badlogic.gdx.utils.GdxRuntimeException: Error loading audio file: mario_music.ogg
              Note: Internal audio files must be placed in the assets directory.
                  at com.badlogic.gdx.backends.android.AndroidAudio.newMusic(AndroidAudio.java:120)
                  at com.badlogic.gdx.assets.loaders.MusicLoader.loadAsync(MusicLoader.java:48)
                  at com.badlogic.gdx.assets.loaders.MusicLoader.loadAsync(MusicLoader.java:29)
                  at com.badlogic.gdx.assets.AssetLoadingTask.call(AssetLoadingTask.java:70)
                  at com.badlogic.gdx.assets.AssetLoadingTask.call(AssetLoadingTask.java:34)
                  at com.badlogic.gdx.utils.async.AsyncExecutor$2.call(AsyncExecutor.java:58)
                  at java.util.concurrent.FutureTask.run(FutureTask.java:237)
                  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
                  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
                  at java.lang.Thread.run(Thread.java:818)
               Caused by: java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed
                  at android.content.res.AssetManager.openAssetFd(Native Method)
                  at android.content.res.AssetManager.openFd(AssetManager.java:346)
                  at com.badlogic.gdx.backends.android.AndroidFileHandle.getAssetFileDescriptor(AndroidFileHandle.java:237)
                  at com.badlogic.gdx.backends.android.AndroidAudio.newMusic(AndroidAudio.java:110)
                  at com.badlogic.gdx.assets.loaders.MusicLoader.loadAsync(MusicLoader.java:48) 
                  at com.badlogic.gdx.assets.loaders.MusicLoader.loadAsync(MusicLoader.java:29) 
                  at com.badlogic.gdx.assets.AssetLoadingTask.call(AssetLoadingTask.java:70) 
                  at com.badlogic.gdx.assets.AssetLoadingTask.call(AssetLoadingTask.java:34) 
                  at com.badlogic.gdx.utils.async.AsyncExecutor$2.call(AsyncExecutor.java:58) 
                  at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
                  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
                  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
                  at java.lang.Thread.run(Thread.java:818) 

如果您绝对希望引号内至少包含一个字符,则需要添加这些前瞻preg_match('~\A[^"\']*+(?:"[^"\\\\]*+(?:\\\\.[^"\\\\]*)*+"[^"\']*|\'[^\'\\\\]*+(?:\\\\.[^\'\\\\]*)*+\'[^"\']*)*+\z~s', $str) (?=[^"])

(?=[^'])

细节:

preg_match('~\A[^"\']*+(?:"(?=[^"])[^"\\\\]*+(?:\\\\.[^"\\\\]*)*+"[^"\']*|\'(?=[^\'])[^\'\\\\]*+(?:\\\\.[^\'\\\\]*)*+\'[^"\']*)*+\z~s', $str)

demo

请注意,这些模式旨在处理转义字符。

大多数情况下,条件可以用简单的替换来替换。

顺便说一句:不要相信较短的图案总是比较长的图案更好,这是一个错误的想法。

答案 1 :(得分:1)

基于下面的两个观察,我构建了我的正则表达式,简单快速,但处理转义引号

  • OP被特别询问字符串$str = "hello, I said: \"How are you?\""是否无效且未回复
  • OP提到的表现(效率作为标准)

我也不是很难阅读的代码粉丝,因此我使用<<< Nowdoc notation来避免以正则表达式模式转义任何内容

我的解决方案:

$strings = [
    "'hello's the word'",
    "'hello is the word'",
    '"hello "there" he said"',
    '"hello there he said"',
    '"Hi',
    "'hello",
    "no quotes",
    "''"
];
$regexp = <<< 'TEXT'
/^('|")(?:(?!\1).)+\1$/
TEXT;
foreach ($strings as $string):
    echo "$string - ".(preg_match($regexp,$string)?'true':'false')."<br/>";
endforeach;

输出:

'hello's the word' - false
'hello is the word' - true
"hello "there" he said" - false
"hello there he said" - true
"Hi - false
'hello - false
no quotes - false
'' - false

工作原理:

^('|")   //starts with single or double-quote
(?:      //non-capturing group
  (?!\1) //next char is not the same as first single/double quote
  .      //advance one character
)+       //repeat group with next char (there must be at least one char)
\1$      //End with the same single or double-quote that started the string