ยุบลำดับของช่องว่างเป็นอักขระเดี่ยวและสตริงตัดแต่ง


122

พิจารณาตัวอย่างต่อไปนี้:

"    Hello      this  is a   long       string!   "

ฉันต้องการแปลงเป็น:

"Hello this is a long string!"

คำตอบ:


125

OS X 10.7+ และ iOS 3.2+

ใช้โซลูชัน regexpดั้งเดิมที่จัดทำโดย hfossli

มิฉะนั้น

ใช้ไลบรารี regexp ที่คุณชื่นชอบหรือใช้ Cocoa-native solution ต่อไปนี้:

NSString *theString = @"    Hello      this  is a   long       string!   ";

NSCharacterSet *whitespaces = [NSCharacterSet whitespaceCharacterSet];
NSPredicate *noEmptyStrings = [NSPredicate predicateWithFormat:@"SELF != ''"];

NSArray *parts = [theString componentsSeparatedByCharactersInSet:whitespaces];
NSArray *filteredArray = [parts filteredArrayUsingPredicate:noEmptyStrings];
theString = [filteredArray componentsJoinedByString:@" "];

4
ฉันอยากรู้เกี่ยวกับการเปรียบเทียบประสิทธิภาพของสิ่งนี้กับการแทนที่ regex ด้วยการตัดแต่งเพื่อลบส่วนท้าย ในแง่หนึ่งคุณมี regex ที่ต้องจัดการ ในทางกลับกันคุณมีเพรดิเคต ต้องการการประมวลผลภายในของนิพจน์ที่เกี่ยวข้อง
— lilbyrdie

@lilbyrdie: ขึ้นอยู่กับสตริงที่ฉันคิดว่ามีช่องว่างกี่ช่อง วิธีแก้ปัญหาของฉันค่อนข้างช้าเพราะสร้างออบเจ็กต์ใหม่สำหรับทุกสตริงย่อยและส่งการเรียกเมธอดไปยังแต่ละรายการ
— Georg Schölly

2
คำตอบที่ดีได้รับการโหวตให้เป็นเช่นนี้ แต่ฉันท้าทายคำจำกัดความของคุณว่า "ง่าย" ขอแสดงความนับถืออดีต Python Guy ตอนนี้อยู่ที่ ObjC-land ;-)
— JK Laiho

2
คุณทำให้ฉันหัวเราะด้วย "อย่าใช้วิธีแก้ปัญหาที่ซับซ้อนถ้ามีวิธีง่ายๆ" วิธีที่ง่ายที่สุดคือ [toBeTrimmed stringByReplacingOccurrencesOfString: @ "" withString: @ ""] ไม่? ฉันยังคงโหวตให้คำตอบของคุณ แต่มันง่ายที่สุดแน่นอน
— Mário Carvalho

2
@ MárioCarvalhoคำถามถามว่าจะลบช่องว่างส่วนเกินได้อย่างไรไม่ใช่ทั้งหมด
— swilliams

52

Regex และ NSCharacterSet พร้อมให้ความช่วยเหลือคุณ โซลูชันนี้จะตัดช่องว่างที่นำหน้าและต่อท้ายตลอดจนช่องว่างหลายช่อง

NSString *original = @"    Hello      this  is a   long       string!   ";

NSString *squashed = [original stringByReplacingOccurrencesOfString:@"[ ]+"
                                                         withString:@" "
                                                            options:NSRegularExpressionSearch
                                                              range:NSMakeRange(0, original.length)];

NSString *final = [squashed stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

การบันทึกfinalให้

"Hello this is a long string!"

รูปแบบ regex ทางเลือกที่เป็นไปได้:

  • แทนที่เฉพาะช่องว่าง: [ ]+
  • แทนที่ช่องว่างและแท็บ: [ \\t]+
  • แทนที่ช่องว่างแท็บและบรรทัดใหม่: \\s+

สรุปประสิทธิภาพ

ความง่ายในการขยายประสิทธิภาพบรรทัดจำนวนโค้ดและจำนวนอ็อบเจ็กต์ที่สร้างขึ้นทำให้โซลูชันนี้เหมาะสม


3
hfossli เป็นคำตอบที่สวยหรูที่สุดในหนังสือของฉัน นอกจากนี้ฉันเพิ่งเรียนรู้ว่าคุณสามารถใช้นิพจน์ทั่วไปในstringByReplacingOccurrencesOfString:. ไม่อยากจะเชื่อเลยว่าฉันไม่รู้
— davidf2281

1
น่ากลัว ทำงานอย่างมีเสน่ห์
— Kushal Ashok

41

จริงๆแล้วมีวิธีง่ายๆในการแก้ไข:

NSString *string = @" spaces in front and at the end ";
NSString *trimmedString = [string stringByTrimmingCharactersInSet:
                                  [NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSLog(@"%@", trimmedString)

( ที่มา )


29
ฉันคิดว่าสิ่งนี้จะกำจัดเฉพาะช่องว่างนำหน้าและต่อท้ายและกำจัดทั้งหมด มันจะไม่จัดการกับ "hello foo"
— Brian Postow

2
d * mn การลงท้ายบรรทัดและรูปแบบอัตโนมัติ ... มันไม่เกี่ยวข้องกับ "hello______foo" (สมมติว่า _ -> "" เพราะการจัดรูปแบบความคิดเห็นทำได้ยาก)
— Brian Postow

32
ทำไมคุณถึงมีคนโหวตให้และคำตอบที่ไม่มีคำตอบสำหรับคำถาม? stringByTrimmingCharactersInSet ไม่ได้วิเคราะห์หรือวิเคราะห์ iside ของสตริง แต่เป็นขอบเท่านั้น คำตอบโดย Georg Sholly เป็นสิ่งที่สมบูรณ์แบบ
— Lukasz

3
ไม่ใช่คำตอบสำหรับคำถาม แต่แน่นอนว่าช่วยฉันได้ ขอบคุณ
— daveMac

1
รหัสที่ยอดเยี่ยมสำหรับการลบช่องว่างด้านหน้าและด้านหลังในเวลาเดียวกัน
— user523234

13

ด้วย regex แต่ไม่จำเป็นต้องใช้กรอบภายนอกใด ๆ :

NSString *theString = @"    Hello      this  is a   long       string!   ";

theString = [theString stringByReplacingOccurrencesOfString:@" +" withString:@" "
                       options:NSRegularExpressionSearch
                       range:NSMakeRange(0, theString.length)];

จากนั้นคุณยังต้องตัดแต่งผลลัพธ์ไม่เช่นนั้นคุณจะถูกบุด้วยช่องว่าง นี่อาจเป็นคำตอบที่ง่ายที่สุด
— lilbyrdie

2
เอกสารประกอบNSRegularExpressionSearchบอกว่าใช้ได้กับrangeOfString:...วิธีการเท่านั้น
— user102008

9

โซลูชันหนึ่งบรรทัด:

NSString *whitespaceString = @" String with whitespaces ";

NSString *trimmedString = [whitespaceString
        stringByReplacingOccurrencesOfString:@" " withString:@""];

2
ช่วยฉันที :) ขอบคุณสำหรับสิ่งนั้น!
— thedom

5
แม้ว่าจะมีประโยชน์ แต่ก็ลบช่องว่างทั้งหมด OP โดยทั่วไปต้องการการบดอัดช่องว่างเช่นการตัดแต่งตามด้วยการลดช่องว่างที่ต่อเนื่องกันเป็นช่องว่างเดียว
— lilbyrdie

หมายเหตุอีกประการหนึ่งโซลูชันนี้ไม่เกี่ยวข้องกับแท็บหรือขึ้นบรรทัดใหม่หรืออักขระเว้นวรรคนอกเหนือจากช่องว่าง
— fwielstra

2
สิ่งนี้ไม่ตอบโจทย์ OP แต่จะลบช่องว่างทั้งหมดในสตริงแทนดังนั้นคุณจึงลงเอยด้วย @ "Stringwithwhitespaces"
— charles

6

สิ่งนี้ควรทำ ...

NSString *s = @"this is    a  string    with lots  of     white space";
NSArray *comps = [s componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

NSMutableArray *words = [NSMutableArray array];
for(NSString *comp in comps) {
  if([comp length] > 1)) {
    [words addObject:comp];
  }
}

NSString *result = [words componentsJoinedByString:@" "];

1
สิ่งนี้ใช้ได้กับสตริง 'a' หรือไม่? มันมีความยาว 1 เท่าที่ฉันเห็นวิธีนี้จะกรองคำที่แยกออกทั้งหมดที่มีขนาด 0 และ 1
— fwielstra

ใช่นั่นคือคำตอบที่ฉันคาดหวัง ขอบคุณ +1
— पवन


3

ลองสิ่งนี้

NSString *theString = @"    Hello      this  is a   long       string!   ";

while ([theString rangeOfString:@"  "].location != NSNotFound) {
    theString = [theString stringByReplacingOccurrencesOfString:@"  " withString:@" "];
}

3

นี่คือตัวอย่างจากNSStringส่วนขยายที่"self"เป็นNSStringตัวอย่าง สามารถใช้เพื่อยุบช่องว่างที่ต่อเนื่องกันให้เป็นช่องว่างเดียวโดยการส่งผ่าน[NSCharacterSet whitespaceAndNewlineCharacterSet]และ' 'ไปยังอาร์กิวเมนต์ทั้งสอง

- (NSString *) stringCollapsingCharacterSet: (NSCharacterSet *) characterSet toCharacter: (unichar) ch {
int fullLength = [self length];
int length = 0;
unichar *newString = malloc(sizeof(unichar) * (fullLength + 1));

BOOL isInCharset = NO;
for (int i = 0; i < fullLength; i++) {
    unichar thisChar = [self characterAtIndex: i];

    if ([characterSet characterIsMember: thisChar]) {
        isInCharset = YES;
    }
    else {
        if (isInCharset) {
            newString[length++] = ch;
        }

        newString[length++] = thisChar;
        isInCharset = NO;
    }
}

newString[length] = '\0';

NSString *result = [NSString stringWithCharacters: newString length: length];

free(newString);

return result;
}

-1

ทางเลือกอื่น: รับสำเนา OgreKit (ไลบรารีนิพจน์ทั่วไปของ Cocoa)

  • OgreKit (หน้าเว็บภาษาญี่ปุ่น - รหัสเป็นภาษาอังกฤษ)
  • OgreKit (การแปลอัตโนมัติของ Google):

จากนั้นฟังก์ชั่นทั้งหมดคือ:

NSString *theStringTrimmed =
   [theString stringByTrimmingCharactersInSet:
        [NSCharacterSet whitespaceAndNewlineCharacterSet]];
OGRegularExpression  *regex =
    [OGRegularExpression regularExpressionWithString:@"\s+"];
return [regex replaceAllMatchesInString:theStringTrimmed withString:@" "]);

สั้นและหวาน

หากคุณต้องการวิธีแก้ปัญหาที่เร็วที่สุดชุดคำแนะนำที่สร้างขึ้นอย่างรอบคอบโดยใช้NSScannerอาจจะได้ผลดีที่สุด แต่จำเป็นก็ต่อเมื่อคุณวางแผนที่จะประมวลผลบล็อกข้อความขนาดใหญ่ (หลายเมกะไบต์)


มีเหตุผลที่จะใช้ OgreKit แทน RegExKitLite หรือไม่? regexkit.sourceforge.net มันมีการเรียก replaceOccurrencesOfRegex ที่คล้ายกันมากและทำงานบนไลบรารี RegEX ที่มีอยู่ (ไม่แน่ใจว่า Ogre เป็นเอนจิ้น RegEX ทั้งหมดหรืออะไร)
— Kendall Helmstetter Gelner

ฉันแน่ใจว่าทั้งสองอย่างจะใช้ได้ ฉันไม่ได้ใช้ regexkit แต่เป็นคำแนะนำที่ดีที่จะทำ ผู้คนควรเลือกโดยพิจารณาจากไลบรารีที่เป็นพื้นฐาน ได้แก่ pcre ที่เข้ากันได้กับ PERL (RegExKitLite) และ Oniguruma (OgreKit) ที่เข้ากันได้กับ Ruby
— Matt Gallagher

-1

อ้างอิงจาก @Mathieu Godart เป็นคำตอบที่ดีที่สุด แต่มีบางบรรทัดขาดหายไปคำตอบทั้งหมดเพียงแค่ลดช่องว่างระหว่างคำ แต่ถ้ามีแท็บหรือมีแท็บอยู่ในช่องว่างเช่นนี้: "นี่คือข้อความ \ t และ \ t แท็บระหว่าง, "ในโค้ดสามบรรทัดเราจะ: สตริงที่เราต้องการลดช่องว่างสีขาว

NSString * str_aLine = @"    this is text \t , and\tTab between      , so on    ";
// replace tabs to space
str_aLine = [str_aLine stringByReplacingOccurrencesOfString:@"\t" withString:@" "];
// reduce spaces to one space
str_aLine = [str_aLine stringByReplacingOccurrencesOfString:@" +" withString:@" "
                                                    options:NSRegularExpressionSearch
                                                      range:NSMakeRange(0, str_aLine.length)];
// trim begin and end from white spaces
str_aLine = [str_aLine stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

ผลลัพธ์คือ

"this is text , and Tab between , so on"

โดยไม่ต้องเปลี่ยนแท็บ resul จะเป็น:

"this is text    , and  Tab between , so on"

-1

คุณยังสามารถใช้อาร์กิวเมนต์ while ไม่มีเวทมนตร์ RegEx อยู่ในนั้นดังนั้นอาจจะเข้าใจง่ายขึ้นและเปลี่ยนแปลงได้ในอนาคต:

while([yourNSStringObject replaceOccurrencesOfString:@"  "
                         withString:@" "
                         options:0
                         range:NSMakeRange(0, [yourNSStringObject length])] > 0);

1
ไม่ตอบคำถาม :) ไม่ลบช่องว่างนำหน้าและต่อท้าย
— hfossli

-1

การทำตามสองนิพจน์ทั่วไปจะได้ผลขึ้นอยู่กับข้อกำหนด

  1. @ "+" สำหรับการจับคู่ช่องว่างและแท็บ
  2. @ "\\ s {2,}" เพื่อจับคู่ช่องว่างแท็บและตัวแบ่งบรรทัด

จากนั้นใช้วิธีการอินสแตนซ์ของ nsstring stringByReplacingOccurrencesOfString:withString:options:range:เพื่อแทนที่ด้วยช่องว่างสีขาวเดียว

เช่น

[string stringByReplacingOccurrencesOfString:regex withString:@" " options:NSRegularExpressionSearch range:NSMakeRange(0, [string length])];

หมายเหตุ: ฉันไม่ได้ใช้ไลบรารี 'RegexKitLite' สำหรับฟังก์ชันข้างต้นสำหรับ iOS 5.x ขึ้นไป


โซลูชันนี้ไม่ได้ลบช่องว่างนำหน้าและต่อท้ายตามที่ OP ขอ
— hfossli

ช่องว่างนำหน้า / ต่อท้าย @hfossli สามารถลบออกได้โดยการเรียกใช้ stringByTrimmingCharactersInSet ของ NSString โดยตรงด้วยชุดอักขระบรรทัดใหม่ / สีขาว วิธีแก้ปัญหาข้างต้นคือการลบช่องว่างที่ซ้ำซ้อนโดยไม่ขึ้นกับตำแหน่งของมัน
— apalvai
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.