Phương thức indexOf (String) có phân biệt chữ hoa chữ thường không? Nếu vậy, có một phiên bản không phân biệt chữ hoa chữ thường không?
Phương thức indexOf (String) có phân biệt chữ hoa chữ thường không? Nếu vậy, có một phiên bản không phân biệt chữ hoa chữ thường không?
Câu trả lời:
Các indexOf()
phương pháp này là tất cả các trường hợp nhạy cảm. Bạn có thể làm cho chúng (đại khái, theo một cách gãy gọn, nhưng hoạt động trong nhiều trường hợp) phân biệt chữ hoa chữ thường bằng cách chuyển đổi các chuỗi của bạn thành chữ hoa / thường trước:
s1 = s1.toLowerCase(Locale.US);
s2 = s2.toLowerCase(Locale.US);
s1.indexOf(s2);
"ß".toUpperCase().equals("SS")
Phương thức indexOf (String) có phân biệt chữ hoa chữ thường không?
Có, nó phân biệt chữ hoa chữ thường:
@Test
public void indexOfIsCaseSensitive() {
assertTrue("Hello World!".indexOf("Hello") != -1);
assertTrue("Hello World!".indexOf("hello") == -1);
}
Nếu vậy, có một phiên bản không phân biệt chữ hoa chữ thường không?
Không, không có. Bạn có thể chuyển đổi cả hai chuỗi thành chữ thường trước khi gọi indexOf:
@Test
public void caseInsensitiveIndexOf() {
assertTrue("Hello World!".toLowerCase().indexOf("Hello".toLowerCase()) != -1);
assertTrue("Hello World!".toLowerCase().indexOf("hello".toLowerCase()) != -1);
}
"ı".toLowerCase(Locale.US).indexOf("I".toLowerCase(Locale.US))
phải trả về 0 vì chuỗi đầu tiên là chữ thường tiếng Thổ Nhĩ Kỳ "I"
, và do đó nên so sánh bằng với chữ hoa "I"
trong chữ thứ hai, nhưng trả về -1 vì chữ sau được chuyển đổi thành "i"
).
Có một phương thức bỏ qua trường hợp trong lớp StringUtils của thư viện Apache Commons Lang
indexOfIgnoreCase (CharSequence str, CharSequence searchStr)
Có, indexOf
có phân biệt chữ hoa chữ thường.
Cách tốt nhất để xử lý trường hợp không phân biệt mà tôi đã tìm thấy là:
String original;
int idx = original.toLowerCase().indexOf(someStr.toLowerCase());
Điều đó sẽ không phân biệt chữ hoa chữ thường indexOf()
.
original.toLowerCase().length()
không phải lúc nào cũng bằng original.length()
. Kết quả idx
là không thể ánh xạ lại một cách chính xác original
.
Đây là giải pháp của tôi không cấp phát bất kỳ bộ nhớ heap nào, do đó nó sẽ nhanh hơn đáng kể so với hầu hết các triển khai khác được đề cập ở đây.
public static int indexOfIgnoreCase(final String haystack,
final String needle) {
if (needle.isEmpty() || haystack.isEmpty()) {
// Fallback to legacy behavior.
return haystack.indexOf(needle);
}
for (int i = 0; i < haystack.length(); ++i) {
// Early out, if possible.
if (i + needle.length() > haystack.length()) {
return -1;
}
// Attempt to match substring starting at position i of haystack.
int j = 0;
int ii = i;
while (ii < haystack.length() && j < needle.length()) {
char c = Character.toLowerCase(haystack.charAt(ii));
char c2 = Character.toLowerCase(needle.charAt(j));
if (c != c2) {
break;
}
j++;
ii++;
}
// Walked all the way to the end of the needle, return the start
// position that this was found.
if (j == needle.length()) {
return i;
}
}
return -1;
}
Và đây là các bài kiểm tra đơn vị để xác minh hành vi đúng.
@Test
public void testIndexOfIgnoreCase() {
assertThat(StringUtils.indexOfIgnoreCase("A", "A"), is(0));
assertThat(StringUtils.indexOfIgnoreCase("a", "A"), is(0));
assertThat(StringUtils.indexOfIgnoreCase("A", "a"), is(0));
assertThat(StringUtils.indexOfIgnoreCase("a", "a"), is(0));
assertThat(StringUtils.indexOfIgnoreCase("a", "ba"), is(-1));
assertThat(StringUtils.indexOfIgnoreCase("ba", "a"), is(1));
assertThat(StringUtils.indexOfIgnoreCase("Royal Blue", " Royal Blue"), is(-1));
assertThat(StringUtils.indexOfIgnoreCase(" Royal Blue", "Royal Blue"), is(1));
assertThat(StringUtils.indexOfIgnoreCase("Royal Blue", "royal"), is(0));
assertThat(StringUtils.indexOfIgnoreCase("Royal Blue", "oyal"), is(1));
assertThat(StringUtils.indexOfIgnoreCase("Royal Blue", "al"), is(3));
assertThat(StringUtils.indexOfIgnoreCase("", "royal"), is(-1));
assertThat(StringUtils.indexOfIgnoreCase("Royal Blue", ""), is(0));
assertThat(StringUtils.indexOfIgnoreCase("Royal Blue", "BLUE"), is(6));
assertThat(StringUtils.indexOfIgnoreCase("Royal Blue", "BIGLONGSTRING"), is(-1));
assertThat(StringUtils.indexOfIgnoreCase("Royal Blue", "Royal Blue LONGSTRING"), is(-1));
}
assertThat(StringUtils.indexOfIgnoreCase("ı" /* Turkish lower-case I, U+0131 */, "I"), is(0));
Có, nó phân biệt chữ hoa chữ thường. Bạn có thể phân biệt chữ hoa chữ thường indexOf
bằng cách chuyển đổi cả hai tham số String và String thành chữ hoa trước khi tìm kiếm.
String str = "Hello world";
String search = "hello";
str.toUpperCase().indexOf(search.toUpperCase());
Lưu ý rằng toUpperCase có thể không hoạt động trong một số trường hợp. Ví dụ:
String str = "Feldbergstraße 23, Mainz";
String find = "mainz";
int idxU = str.toUpperCase().indexOf (find.toUpperCase ());
int idxL = str.toLowerCase().indexOf (find.toLowerCase ());
idxU sẽ là 20, điều này là sai! idxL sẽ là 19, chính xác. Nguyên nhân gây ra sự cố là tha toUpperCase () chuyển đổi ký tự "ß" thành HAI ký tự, "SS" và điều này làm tắt chỉ mục.
Do đó, hãy luôn gắn bó với toLowerCase ()
find
thành "STRASSE"
, nó hoàn toàn không tìm thấy nó trong biến thể chữ thường, nhưng lại tìm thấy nó một cách chính xác trong phiên bản chữ hoa.
Bạn đang làm gì với giá trị chỉ mục khi được trả về?
Nếu bạn đang sử dụng nó để thao tác chuỗi của mình, thì bạn có thể không sử dụng một biểu thức chính quy được không?
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class StringIndexOfRegexpTest {
@Test
public void testNastyIndexOfBasedReplace() {
final String source = "Hello World";
final int index = source.toLowerCase().indexOf("hello".toLowerCase());
final String target = "Hi".concat(source.substring(index
+ "hello".length(), source.length()));
assertEquals("Hi World", target);
}
@Test
public void testSimpleRegexpBasedReplace() {
final String source = "Hello World";
final String target = source.replaceFirst("(?i)hello", "Hi");
assertEquals("Hi World", target);
}
}
Tôi vừa xem nguồn. Nó so sánh các ký tự nên phân biệt chữ hoa chữ thường.
@Test
public void testIndexofCaseSensitive() {
TestCase.assertEquals(-1, "abcDef".indexOf("d") );
}
Có cùng một vấn đề. Tôi đã thử biểu thức chính quy và apache StringUtils.indexOfIgnoreCase-Method, nhưng cả hai đều khá chậm ... Vì vậy, tôi đã tự viết một phương thức ngắn ...:
public static int indexOfIgnoreCase(final String chkstr, final String searchStr, int i) {
if (chkstr != null && searchStr != null && i > -1) {
int serchStrLength = searchStr.length();
char[] searchCharLc = new char[serchStrLength];
char[] searchCharUc = new char[serchStrLength];
searchStr.toUpperCase().getChars(0, serchStrLength, searchCharUc, 0);
searchStr.toLowerCase().getChars(0, serchStrLength, searchCharLc, 0);
int j = 0;
for (int checkStrLength = chkstr.length(); i < checkStrLength; i++) {
char charAt = chkstr.charAt(i);
if (charAt == searchCharLc[j] || charAt == searchCharUc[j]) {
if (++j == serchStrLength) {
return i - j + 1;
}
} else { // faster than: else if (j != 0) {
i = i - j;
j = 0;
}
}
}
return -1;
}
Theo thử nghiệm của tôi, nó nhanh hơn nhiều ... (ít nhất là nếu chuỗi tìm kiếm của bạn khá ngắn). Nếu bạn có bất kỳ đề xuất nào để cải thiện hoặc có lỗi, rất vui nếu bạn cho tôi biết ... (vì tôi sử dụng mã này trong một ứng dụng ;-)
indexOfIgnoreCase("İ","i")
nên trả về 0 vì İ
cách viết hoa chính xác của i
văn bản tiếng Thổ Nhĩ Kỳ, nhưng thay vào đó trả về -1 vì i
được viết hoa phổ biến hơn I
).
Câu hỏi đầu tiên đã được trả lời nhiều lần. Có, String.indexOf()
tất cả các phương pháp đều phân biệt chữ hoa chữ thường.
Nếu bạn cần một ngôn ngữ nhạy cảm, indexOf()
bạn có thể sử dụng Collator . Tùy thuộc vào giá trị cường độ bạn đặt, bạn có thể nhận được so sánh không phân biệt chữ hoa chữ thường và cũng coi các chữ cái có dấu giống như chữ cái không dấu, v.v. Dưới đây là một ví dụ về cách thực hiện điều này:
private int indexOf(String original, String search) {
Collator collator = Collator.getInstance();
collator.setStrength(Collator.PRIMARY);
for (int i = 0; i <= original.length() - search.length(); i++) {
if (collator.equals(search, original.substring(i, i + search.length()))) {
return i;
}
}
return -1;
}
Nhưng không khó để viết một:
public class CaseInsensitiveIndexOfTest extends TestCase {
public void testOne() throws Exception {
assertEquals(2, caseInsensitiveIndexOf("ABC", "xxabcdef"));
}
public static int caseInsensitiveIndexOf(String substring, String string) {
return string.toLowerCase().indexOf(substring.toLowerCase());
}
}
"ı"
là biến thể viết thường (không phải là biến thể mặc định trong hầu hết các ngôn ngữ) của "I"
. Hoặc cách khác, nếu chạy trên một máy được đặt thành ngôn ngữ "ı"
là mặc định, nó sẽ không nhận thấy rằng đó "i"
cũng là một biến thể chữ thường của "I"
.
Chuyển đổi cả hai chuỗi thành chữ thường thường không phải là vấn đề lớn nhưng sẽ rất chậm nếu một số chuỗi dài. Và nếu bạn làm điều này trong một vòng lặp thì nó sẽ thực sự tồi tệ. Vì lý do này, tôi muốn giới thiệu indexOfIgnoreCase
.
static string Search(string factMessage, string b)
{
int index = factMessage.IndexOf(b, StringComparison.CurrentCultureIgnoreCase);
string line = null;
int i = index;
if (i == -1)
{ return "not matched"; }
else
{
while (factMessage[i] != ' ')
{
line = line + factMessage[i];
i++;
}
return line;
}
}
Đây là một phiên bản gần giống với phiên bản StringUtils của Apache:
public int indexOfIgnoreCase(String str, String searchStr) {
return indexOfIgnoreCase(str, searchStr, 0);
}
public int indexOfIgnoreCase(String str, String searchStr, int fromIndex) {
// /programming/14018478/string-contains-ignore-case/14018511
if(str == null || searchStr == null) return -1;
if (searchStr.length() == 0) return fromIndex; // empty string found; use same behavior as Apache StringUtils
final int endLimit = str.length() - searchStr.length() + 1;
for (int i = fromIndex; i < endLimit; i++) {
if (str.regionMatches(true, i, searchStr, 0, searchStr.length())) return i;
}
return -1;
}
Tôi muốn đưa ra yêu cầu đối với giải pháp DUY NHẤT và duy nhất được đăng cho đến nay thực sự hoạt động. :-)
Ba lớp của các vấn đề phải được xử lý.
Quy tắc đối sánh không bắc cầu cho chữ thường và chữ hoa. Vấn đề tiếng Thổ Nhĩ Kỳ I đã được đề cập thường xuyên trong các bài trả lời khác. Theo nhận xét trong nguồn Android cho String.regionMatches, các quy tắc so sánh của Georgia yêu cầu chuyển đổi bổ sung thành chữ thường khi so sánh để có bình đẳng phân biệt chữ hoa chữ thường.
Các trường hợp mà dạng viết hoa và viết thường có số lượng chữ cái khác nhau. Khá nhiều giải pháp đã đăng cho đến nay đều thất bại, trong những trường hợp này. Ví dụ: STRASSE của Đức và Straße có bằng nhau không phân biệt chữ hoa chữ thường, nhưng có độ dài khác nhau.
Độ mạnh ràng buộc của các ký tự có dấu. Ngôn ngữ VÀ hiệu ứng ngữ cảnh cho dù trọng âm có khớp hay không. Trong tiếng Pháp, dạng viết hoa của 'é' là 'E', mặc dù có một xu hướng sử dụng trọng âm hoa. Trong tiếng Pháp Canada, dạng viết hoa của 'é' là 'É', không có ngoại lệ. Người dùng ở cả hai quốc gia sẽ mong đợi "e" khớp với "é" khi tìm kiếm. Các ký tự có dấu và không có dấu có khớp với nhau theo ngôn ngữ cụ thể hay không. Bây giờ hãy xem xét: "E" có bằng "É" không? Đúng. Nó có. Bằng tiếng Pháp, dù sao.
Tôi hiện đang sử dụng android.icu.text.StringSearch
để triển khai chính xác các triển khai trước đây của các hoạt động indexOf không phân biệt chữ hoa chữ thường.
Người dùng không phải Android có thể truy cập cùng một chức năng thông qua gói ICU4J, sử dụng com.ibm.icu.text.StringSearch
lớp.
Hãy cẩn thận tham chiếu các lớp trong gói icu chính xác ( android.icu.text
hoặc com.ibm.icu.text
) vì Android và JRE đều có các lớp có cùng tên trong các không gian tên khác (ví dụ: Collator).
this.collator = (RuleBasedCollator)Collator.getInstance(locale);
this.collator.setStrength(Collator.PRIMARY);
....
StringSearch search = new StringSearch(
pattern,
new StringCharacterIterator(targetText),
collator);
int index = search.first();
if (index != SearchString.DONE)
{
// remember that the match length may NOT equal the pattern length.
length = search.getMatchLength();
....
}
Các trường hợp thử nghiệm (Ngôn ngữ, mẫu, văn bản đích, kết quả mong đợi):
testMatch(Locale.US,"AbCde","aBcDe",true);
testMatch(Locale.US,"éèê","EEE",true);
testMatch(Locale.GERMAN,"STRASSE","Straße",true);
testMatch(Locale.FRENCH,"éèê","EEE",true);
testMatch(Locale.FRENCH,"EEE","éèê",true);
testMatch(Locale.FRENCH,"éèê","ÉÈÊ",true);
testMatch(new Locale("tr-TR"),"TITLE","tıtle",true); // Turkish dotless I/i
testMatch(new Locale("tr-TR"),"TİTLE","title",true); // Turkish dotted I/i
testMatch(new Locale("tr-TR"),"TITLE","title",false); // Dotless-I != dotted i.
Tái bút: Tốt nhất tôi có thể xác định, độ mạnh ràng buộc CHÍNH nên làm đúng khi các quy tắc theo ngôn ngữ cụ thể phân biệt giữa các ký tự có dấu và không trọng âm theo quy tắc từ điển; nhưng tôi không sử dụng ngôn ngữ nào để kiểm tra tiền đề này. Các trường hợp thử nghiệm được tặng sẽ được đánh giá cao.
indexOf phân biệt chữ hoa chữ thường. Điều này là do nó sử dụng phương thức bằng để so sánh các phần tử trong danh sách. Điều tương tự cũng xảy ra với hàm chứa và loại bỏ.