Ist das ein Feature oder ein Bug von clang c++11 std::regex_match?

Ist das ein Feature oder ein Bug von clang c++11 std::regex_match?


Ich habe festgestellt, dass ein regulärer Ausdruck, der zwei Muster mit einer ODER-Bedingung enthält, nicht mit einer Musterzeichenfolge übereinstimmt, wenn das erste Muster ein Anfangsteil des zweiten Musters ist (getestet auf clang 3.5 und clang 3.8):


std::regex_match("ab", std::regex("(ab|a)")) == true

aber


std::regex_match("ab", std::regex("(a|ab)")) == false

Ich denke true ist in beiden Fällen logisch korrekt.


Clang &OSX:


$ cat > test.cpp
#include <string>
#include <regex>
#include <iostream>
int main() {
std::cout << std::regex_match("ab", std::regex("(a|ab)")) << std::endl;
std::cout << std::regex_match("ab", std::regex("(ab|a)")) << std::endl;
return 0;
}
^C
$ clang++ -v
Apple LLVM version 8.1.0 (clang-802.0.41)
Target: x86_64-apple-darwin16.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
$ clang++ ./test.cpp -o test
$ ./test
0
1

Clang &FreeBSD:


$ cat > test.cpp
#include <string>
#include <regex>
#include <iostream>
int main() {
std::cout << std::regex_match("ab", std::regex("(a|ab)")) << std::endl;
std::cout << std::regex_match("ab", std::regex("(ab|a)")) << std::endl;
return 0;
}
^C
$ clang++ -v
FreeBSD clang version 3.8.0 (tags/RELEASE_380/final 262564) (based on LLVM 3.8.0)
Target: x86_64-unknown-freebsd11.0
Thread model: posix
InstalledDir: /usr/bin
$ clang++ ./test.cpp -o test
$ ./test
0
1

Linux &GCC:


$ cat > test.cpp
#include <string>
#include <regex>
#include <iostream>
int main() {
std::cout << std::regex_match("ab", std::regex("(a|ab)")) << std::endl;
std::cout << std::regex_match("ab", std::regex("(ab|a)")) << std::endl;
return 0;
}
^C
$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 5.4.1-2ubuntu1~16.04' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 5.4.1 20160904 (Ubuntu 5.4.1-2ubuntu1~16.04)
$ g++ -std=gnu++11 ./test.cpp -o test
$ ./test
1
1

Gefragt von Max Fomichev

Antworten:


ECMAScript (die standardmäßige Regex-Syntax) versucht, die Alternativen der Reihe nach abzugleichen, und stoppt beim ersten Erfolg, was bedeutet, dass bei einer gewöhnlichen Suche (a la regex_search ) die Regex a|ab stimmt nie mit den ganzen ab überein; es stimmt immer nur mit a überein Teil.


Der Standard war mehrdeutig darüber, was regex_match ist in diesem Fall tun sollte, was zu Abweichungen bei der Implementierung führte. Siehe LWG Issue 2273 für die konkurrierenden Interpretationen. Schließlich wurde der Standard geändert (siehe Lösung dieses Problems), um klarzustellen, dass regex_match berücksichtigt nur potenzielle Übereinstimmungen, die mit der gesamten Eingabesequenz übereinstimmen, wie das dem Standard hinzugefügte Beispiel deutlich macht:


std::regex re("Get|GetValue");
std::cmatch m;
regex_search("GetValue", m, re); // returns true, and m[0] contains "Get"
regex_match ("GetValue", m, re); // returns true, and m[0] contains "GetValue"

Das Original <regex> Die Implementierung in libc++ verwendete jedoch die andere Interpretation und wurde bis vor kurzem einfach nicht aktualisiert, um der Auflösung zu entsprechen. Clang 4.0 gibt jetzt 1 1 aus .


Einige Code-Antworten


std::regex_match("ab", std::regex("(ab|a)")) == true 
std::regex_match("ab", std::regex("(a|ab)")) == false 
$ cat >
test.cpp #include <string>
#include <regex>
#include <iostream>
int main() {
std::cout <<
std::regex_match("ab", std::regex("(a|ab)")) <<
std::endl;
std::cout <<
std::regex_match("ab", std::regex("(ab|a)")) <<
std::endl;
return 0;
} ^C $ clang++ -v Apple LLVM version 8.1.0 (clang-802.0.41) Target: x86_64-apple-darwin16.5.0 Thread model: posix InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin $ clang++ ./test.cpp -o test $ ./test 0 1
$ cat >
test.cpp #include <string>
#include <regex>
#include <iostream>
int main() {
std::cout <<
std::regex_match("ab", std::regex("(a|ab)")) <<
std::endl;
std::cout <<
std::regex_match("ab", std::regex("(ab|a)")) <<
std::endl;
return 0;
} ^C $ clang++ -v FreeBSD clang version 3.8.0 (tags/RELEASE_380/final 262564) (based on LLVM 3.8.0) Target: x86_64-unknown-freebsd11.0 Thread model: posix InstalledDir: /usr/bin $ clang++ ./test.cpp -o test $ ./test 0 1
$ cat >
test.cpp #include <string>
#include <regex>
#include <iostream>
int main() {
std::cout <<
std::regex_match("ab", std::regex("(a|ab)")) <<
std::endl;
std::cout <<
std::regex_match("ab", std::regex("(ab|a)")) <<
std::endl;
return 0;
} ^C $ g++ -v Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 5.4.1-2ubuntu1~16.04' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 5.4.1 20160904 (Ubuntu 5.4.1-2ubuntu1~16.04) $ g++ -std=gnu++11 ./test.cpp -o test $ ./test 1 1
std::regex re("Get|GetValue");
std::cmatch m;
regex_search("GetValue", m, re);
// returns true, and m[0] contains "Get" regex_match ("GetValue", m, re);
// returns true, and m[0] contains "GetValue"